私は今までブロックについてかなり読んできました.Appleのガイド、Cocoabuilder、SOに関する3つの記事と、基本的にオンラインチュートリアルから得たコードの例を使用しています。私はまだ1つの特定の質問を理解しようとしています. そこで、理解を深めるために、completionHandler の例だけでアプリを作成することにしました。これは私が思いついたものです:
ViewController
- (void)viewDidLoad
[SantiappsHelper fetchUsersWithCompletionHandler:^(NSArray *users) {
self.usersArray = [NSMutableArray array];
for (NSDictionary *userDict in users) {
[self.usersArray addObject:[userDict objectForKey:@"username"]];
}
//WHILE TESTING postarray method, comment this out...
//[self getPoints];
[self.tableView reloadData];
}];
}
SantiappsHelper.h/m
typedef void (^Handler)(NSArray *users);
+(void)fetchUsersWithCompletionHandler:(Handler)handler {
NSString *urlString = [NSString stringWithFormat:@"http://www.myserver.com/myapp/getusers.php"];
NSURL *url = [NSURL URLWithString:urlString];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:10];
[request setHTTPMethod: @"GET"];
__block NSArray *usersArray = [[NSArray alloc] init];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
//dispatch_async(dispatch_get_main_queue(), ^{
// Peform the request
NSURLResponse *response;
NSError *error = nil;
NSData *receivedData = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
if (error) {
// Deal with your error
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
return;
}
NSLog(@"Error %@", error);
return;
}
NSString *responseString = [[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding];
usersArray = [NSJSONSerialization JSONObjectWithData:[responseString dataUsingEncoding:NSASCIIStringEncoding] options:0 error:nil];
if (handler){
//dispatch_sync WAITS for the block to complete before returning the value
//otherwise, the array is returned but gets zeroed out
dispatch_sync(dispatch_get_main_queue(), ^{
handler(usersArray);
});
}
});
}
これが私が理解していることです...
VC から fetchUsersWithCompletionHandler を呼び出し、この完了ブロックを渡します。そのブロックは NSArray ユーザー パラメータを受け取り、void を返します。
一方、SantiappsHelper クラスには、VC から受け取るタイプ ^block の handler と呼ばれる変数があります。
fetchUsersWithCompletionHandler メソッドが実行され、その CompletionBlock パラメータを取得します。これは、NSArray users パラメータを取得しますか? 少し混乱します。
webfetch は dispatch_async であるため、メイン スレッドをブロックしません。そのため、メイン スレッドでの実行が続行されます。その新しいスレッドはフェッチを同期的に実行し、その新しいスレッドは応答が返されるまで停止します。その新しいスレッドが応答を受信すると、NSHTTPURLResponse に入力します。返されると、usersArray に NSJSONSerialized データが入力されます。
最後に if テストに到達し、渡された PARAMETER ハンドラの存在をチェックしますか? 少し紛らわしいです...渡されたパラメーターは、completionBlock でした。そのハンドラーパラメーターは、渡されてから常に存在しているでしょうか?
ハンドラが !NULL になると、実行がメイン スレッドに返され、ブロックによって期待される NSArray ユーザーが VC に返されます。
しかし、2 番目のディスパッチを非同期に変更すると、usersArray は適切に設定されますが、handler(usersArray) がメイン スレッドに送り返されると、空または nil になります。なんで?