到目前为止,我已经阅读了很多关于块的内容,Apple的指南,Cocoabuilder,3篇关于SO和ive的文章在我的代码中使用了我基本上从在线教程中获得的示例。我仍然试图理解一个具体的问题。所以我决定创建一个只有一个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 /米
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用户参数&返回无效。
同时在SantiappsHelper类中,我们有一个名为^ block的处理程序的变量,它从VC接收。
fetchUsersWithCompletionHandler方法运行,获取CompletionBlock参数,该参数本身采用NSArray用户参数?有点混乱。
webfetch是dispatch_async所以它不会阻塞主线程。因此继续在主线程上执行。新线程同步执行获取,新线程将停止,直到返回响应。一旦新线程收到响应,它就会填写NSHTTPURLResponse。一旦它返回,它就会用NSJSONSerialized数据填充usersArray。
最后它到达if测试并检查是否存在传入的PARAMETER处理程序?有点令人困惑......传入的参数是completionBlock。自从它传入以来,处理程序参数总是显而易见存在吗?
一旦处理程序!NULL,则执行返回到主线程,将该块所需的NSArray用户传回VC中。
但是如果我将第二次调度更改为异步,则usersArray已正确填充,但一旦处理程序(usersArray)被发送回主线程,则为空或零!为什么呢?
答案 0 :(得分:2)
正确。说/思考这个问题的最佳方式是说你正在调用一个名为fetchUsersWithCompletionHandler:
的方法。这个方法将消失并做一些工作,并且在将来的某个时候它可能会执行你在块文字中声明的代码并传入一组用户。
该方法采用名为handler
的{{1}}类型的参数。此类型表示一个代码块,在调用时应接收并返回数组并且不返回任何结果。
void (^)(NSArray *users)
做了一些工作,并且在某些时候可以调用用一组用户传入的块作为块参数。
正确
fetchUsersWithCompletionHandler:
检查处理程序参数是否不是if (handler) {
。在大多数情况下,情况尤其如此,如果你总是用块文字调用nil
,但是你总是可以用fetchUsersWithCompletionHandler:
调用方法,或者调用它来传递来自其他地方的变量作为完成,可以是[self fetchUsersWithCompletionHandler:nil];
。如果您尝试取消引用nil
来调用它,那么您将崩溃。
执行不会“传回”到主线程,您只是将要在主线程上执行的工作块排入队列。您正在使用nil
调用来执行此操作,这将阻止此后台线程直到块完成 - 这不是真正需要的。
数组为dispatch_sync
可能是您声明nil
存储usersArray
的结果。这不是必需的,因为你没有修改__block
指向的任何一点,你只是在它上面调用方法。