方法在完成处理程序之前返回

我正在为我的项目开发一个networkUtil,我需要一个获取url的方法,并使用NSURLSessionDataTask从该URL返回从该服务器获取JSON的JSON。 方法如下:

+ (NSDictionary*) getJsonDataFromURL:(NSString *)urlString{ __block NSDictionary* jsonResponse; NSURLSession *session = [NSURLSession sharedSession]; NSURLSessionDataTask *dataTask = [session dataTaskWithURL:[NSURL URLWithString:urlString] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; NSLog(@"%@", jsonResponse); }]; [dataTask resume]; return jsonResponse; } 

问题是在我的方法和方法本身completionHandler运行在不同的线程和最后一行jsonResponse总是

我应该如何设置jsonResponseurlString返回的json?
这个问题的最佳做法是什么?

在NSURLSession中运行的块在不同的线程上运行 – 您的方法不会等待块完成。

你有两个select

第一个 发送NSNotification

 + (void) getJsonDataFromURL:(NSString *)urlString{ NSURLSession *session = [NSURLSession sharedSession]; NSURLSessionDataTask *dataTask = [session dataTaskWithURL:[NSURL URLWithString:urlString] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { NSDictionary* jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; NSLog(@"%@", jsonResponse); [[NSNotificationCenter defaultCenter] postNotificationName:@"JSONResponse" object:nil userInfo:@{@"response" : jsonResponse}]; }]; [dataTask resume]; } 

第二个 此实用程序方法的过去完成块

 + (void) getJsonDataFromURL:(NSString *)urlString completionBlock:(void(^)(NSDictionary* response))completion { NSURLSession *session = [NSURLSession sharedSession]; NSURLSessionDataTask *dataTask = [session dataTaskWithURL:[NSURL URLWithString:urlString] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { NSDictionary* jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; NSLog(@"%@", jsonResponse); completion(jsonResponse); }]; [dataTask resume]; } 

有些人可能会说这是一个可怕的build议,但你也可以同步下载你的数据。 应该在后台队列中完成。 这不是一个好的做法,但对于某些情况(如命令行实用程序,非关键的后台队列),这是可以的。

NSURLSession没有同步下载的方法,但你可以很容易地绕过信号量:

 + (NSDictionary*) getJsonDataFromURL:(NSString *)urlString{ __block NSDictionary* jsonResponse; dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); // Line 1 NSURLSession *session = [NSURLSession sharedSession]; NSURLSessionDataTask *dataTask = [session dataTaskWithURL:[NSURL URLWithString:urlString] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; NSLog(@"%@", jsonResponse); dispatch_semaphore_signal(semaphore); // Line 2 }]; [dataTask resume]; dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); // Line 3 return jsonResponse; } 

NSURLSession有一个delegateQueue属性,用于“与会话相关的委托方法调用和完成处理程序”。 默认情况下,NSURLSession在初始化时总是创build一个新的delegateQueue。 但是,如果您自己设置NSURLSession的委托队列,请确保不要在同一队列中调用您的方法,因为它会阻止它。

这是“asynchronous调用”的预期行为。 他们不应该阻塞调用线程,而是在调用完成时执行传递的块。

在块中获得结果后,只需添加必须执行的代码即可。

所以,而不是…

 + (NSDictionary*) getJsonDataFromURL:(NSString *)urlString { __block NSDictionary* jsonResponse; NSURLSession *session = [NSURLSession sharedSession]; NSURLSessionDataTask *dataTask = [session dataTaskWithURL:[NSURL URLWithString:urlString] completionHandler: ^(NSData *data, NSURLResponse *response, NSError *error) { jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; NSLog(@"%@", jsonResponse); }]; [dataTask resume]; return jsonResponse; } … NSDictionary* jsonResponde = [self getJsonDataFromURL:url]; // BTW: get infringes the naming rules of Objective-C // The code that has to be executed is here 

… 你做这个:

 + (void) getJsonDataFromURL:(NSString *)urlString { NSURLSession *session = [NSURLSession sharedSession]; NSURLSessionDataTask *dataTask = [session dataTaskWithURL:[NSURL URLWithString:urlString] completionHandler: ^(NSData *data, NSURLResponse *response, NSError *error) { NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; NSLog(@"%@", jsonResponse); // Place the code to be executed here <----- }]; [dataTask resume]; } … [self getJsonDataFromURL:url]; // BTW: get infringes the naming rules of Objective-C // No code here any more 

如果由-getJsonDataFromURL:执行的代码依赖于调用者,只需将其作为parameter passing给方法并在指定的位置执行。 如果您需要帮助,请告诉我。 我将添加它的代码。

另一个解决scheme是使用信号量并等待,直到执行完成处理程序。 但是这会阻止用户界面,并不是有意的方式来做到这一点。

很明显方法将在块完成之前返回。 因为这是块的主要目的。

你需要改变这样的事情:

 NSDictionary* jsonResponse; + (NSDictionary*) getJsonDataFromURL:(NSString *)urlString{ NSURLSession *session = [NSURLSession sharedSession]; NSURLSessionDataTask *dataTask = [session dataTaskWithURL:[NSURL URLWithString:urlString] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { self.jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; NSLog(@"%@", jsonResponse); [dataTask resume]; // ad observer here that call method to update your UI }]; }