2013-12-09 18 views
8

私はanother similar questionがあることを知っていますが、これはAFNetworkingの古いバージョン用であり、とにかくそれには本当に答えるものではありません。AFNetworking-2 waitUntilFinishedが動作しない

私は、次のコードをしている:私はこれを実行する場合

AFHTTPRequestOperationManager* manager = [AFHTTPRequestOperationManager manager]; 
manager.securityPolicy.allowInvalidCertificates = YES; 
manager.requestSerializer = [AFJSONRequestSerializer serializer]; 
[manager.requestSerializer setAuthorizationHeaderFieldWithUsername: currentUser() password: currentPassword()]; 
__block NSDictionary* response = nil; 
AFHTTPRequestOperation* operation = [manager 
    GET: @"https://10.20.30.40:8765/foobar" 
    parameters: [NSDictionary dictionary] 
    success:^(AFHTTPRequestOperation* operation, id responseObject){ 
     response = responseObject; 
     NSLog(@"response (block): %@", response); 
    } 
    failure:^(AFHTTPRequestOperation* operation, NSError* error){ 
     NSLog(@"Error: %@", error);} 
]; 
[operation waitUntilFinished]; 
NSLog(@"response: %@", response); 
... 

、私は私のログに何が表示されますは、次のとおりです。

2013-12-09 09:26:20.105 myValve[409:60b] response: (null) 
2013-12-09 09:26:20.202 myValve[409:60b] response (block): { 
    F00005 = ""; 
    F00008 = ""; 
    F00013 = ""; 
} 

最初waitUntilFinished火災でNSLog 。私はそれが二番目に発射することを期待した。私は何が欠けていますか?

答えて

32

思考のカップル:

  1. 問題がwaitUntilFinishedを完了するために、コアネットワークの操作を待つだろうが、それはsuccessまたはfailure完了ブロックを待たないであろうということです。でsemaphoreを排除し、あなたが、その代わりに、AFHTTPRequestOperation完了ブロックでisFinishedを投稿し、あなた自身の同時NSOperationサブクラスでこれをラップすることができます

    __block NSDictionary* response = nil; 
    
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); 
    
    manager.completionQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 
    
    AFHTTPRequestOperation* operation = [manager GET: @"https://10.20.30.40:8765/foobar" 
                 parameters: [NSDictionary dictionary] 
                 success:^(AFHTTPRequestOperation* operation, id responseObject){ 
                  response = responseObject; 
                  NSLog(@"response (block): %@", response); 
                  dispatch_semaphore_signal(semaphore); 
                 } 
                 failure:^(AFHTTPRequestOperation* operation, NSError* error){ 
                  NSLog(@"Error: %@", error); 
                  dispatch_semaphore_signal(semaphore); 
                 }]; 
    
    NSLog(@"waiting"); 
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); 
    // [operation waitUntilFinished]; 
    NSLog(@"response: %@", response); 
    

    :あなたが完了ブロックを待つしたい場合は、セマフォを使用することができますプロセス。

    メインキュー でセマフォを実行する場合は、AFNetworkingがデフォルトでメインキューに完了ハンドラをディスパッチし、デッドロックする可能性があるため、必ず指定してください。

  2. 脇に、メインキュー(貧弱なUX、あなたのアプリはウォッチドッグプロセスなどで殺される可能性があります)をブロックしてはいけないので、メインキューからこれをやっていると、 waitUntilFinishedまたはセマフォのいずれかを使用します。それはちょうど、例えば、この非同期ネットワーク操作の進行中に、メインキューが実行を継続させる、あなたが完了ブロックの中から必要なものは何でも開始すると良いでしょう:

    [activityIndicatorView startAnimating]; 
    
    AFHTTPRequestOperation* operation = [manager GET: @"https://10.20.30.40:8765/foobar" 
                 parameters: [NSDictionary dictionary] 
                 success:^(AFHTTPRequestOperation* operation, id responseObject){ 
    
                  // do whatever you want with `responseObject` here 
    
                  // now update the UI, e.g.: 
    
                  [activityIndicatorView stopAnimating]; 
                  [self.tableView reloadData]; 
                 } 
                 failure:^(AFHTTPRequestOperation* operation, NSError* error){ 
    
                  // put your error handling here 
    
                  // now update the UI, e.g.: 
    
                  [activityIndicatorView stopAnimating]; 
                 }]; 
    
    // NSLog(@"waiting"); 
    // dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); 
    // // [operation waitUntilFinished]; 
    // NSLog(@"response: %@", response); 
    

あなたがしたいようですねモデルオブジェクトの更新が完了したときにモデルがUIに必要な更新を行わせるようにします。そのため、独自のブロックパラメータを使用して、ビューコントローラが完了したときに何をすべきかをモデルオブジェクトに伝えることができます(waitUntilFinishedまたはセマフォを使用してメインキューをブロックする)。たとえば、のは、あなたのモデルは、このようないくつかのメソッドを持っていたと仮定しましょう:

- (void)updateModelWithSuccess:(void (^)(void))success failure:(void (^)(NSError *error))failure 
{ 
    AFHTTPRequestOperationManager* manager = [AFHTTPRequestOperationManager manager]; 
    manager.securityPolicy.allowInvalidCertificates = YES; 
    manager.requestSerializer = [AFJSONRequestSerializer serializer]; 
    [manager.requestSerializer setAuthorizationHeaderFieldWithUsername: currentUser() password: currentPassword()]; 
    AFHTTPRequestOperation* operation = [manager GET: @"https://10.20.30.40:8765/foobar" 
              parameters: [NSDictionary dictionary] 
              success:^(AFHTTPRequestOperation* operation, id responseObject){ 

               // do your model update here 

               // then call the success block passed to this method (if any), 
               // for example to update the UI 

               if (success) 
                success(); 
              } 
              failure:^(AFHTTPRequestOperation* operation, NSError* error){ 
               NSLog(@"Error: %@", error); 

               // if caller provided a failure block, call that 

               if (failure) 
                failure(error); 
              }]; 
} 

その後、あなたのビューコントローラのようなものを行うことができます。

[modelObject updateModelWithSuccess:^{ 
    // specify UI updates to perform upon success, e.g. 
    // stop activity indicator view, reload table, etc. 
} failure:^(NSError *error){ 
    // specify any UI updates to perform upon failure 
}] 

ボトムラインを、あなたのコードは、その補完ブロックの同じスタイルを使用することができますAFNetworkingが使用します。モデルが情報を返すようにするには、補完ブロック自体にパラメータを追加することができますが、上では基本的な考え方を示しています。

+4

残念ながら、オプション#1は物事を完全にハングアップします。どちらもブロックすることはありません。なぜそれを置くのかは分かりませんが、そうしています。 –

+0

私は「UIがぶら下がっている」ということを理解しています。このケースで私が苦労しているのは、ローカルモデルを更新するためのRESTクエリです。だから私は、このAFのものをモデルクラスに入れて更新をしたいと思っています。そこで、私は、andWhenYourDone:ブロックを使用してこれらのメソッドを拡張しなければならなくなり、必要に応じてUIの更新をトリガーすることができます。 –

+0

@TravisGriggsそして、あなたのモデルの 'updateModel'メソッドブロックパラメータを与えてください(AFNetworking自身が使用する' success'ブロックと 'failure'ブロックと違うものではありません)。このようにして、ビューコントローラーは効果的に「モデルを更新し、終了したらx、y、zを実行する」と言うことができます。改訂版の回答を参照してください。 – Rob