NSURLSessionDataTask用于HTTP数据任务的话,它是否在后台线程中运行或者我们需要提供队列?

23

我开始使用NSURLSession,现在避免使用NSURLConnection,因为这是苹果提供的新的优秀API。 以前,我曾经将调用NSURLRequest放入GCD块中以在后台执行它。以下是我过去的做法:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

    NSURL *url = [NSURL URLWithString:@"www.stackoverflow.com"];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    NSURLResponse *response;
    NSError *error;
    NSData *data = [NSURLConnection sendSynchronousRequest:request 
                                         returningResponse:&response 
                                                     error:&error];
    if (error) {
        // Handle error
        return;
    }
    dispatch_async(dispatch_get_main_queue(), ^{
        // Do something with the data
    });
});

现在,我来介绍如何使用 NSURLSession

- (void)viewDidLoad 
{
    [super viewDidLoad];
 
    /*-----------------*
        NSURLSession
     *-----------------*/

    NSURL *url = [NSURL URLWithString:@"https://itunes.apple.com/search?term=apple&media=software"];

    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *dataTask = [session dataTaskWithURL:url
                                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) 
    {
        NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data 
                                                             options:0
                                                               error:nil];
        NSLog(@"%@", json);
    }];
}

我想知道,我的请求会在后台线程上执行,还是我需要提供自己的机制,就像我在使用NSURLRequest时一样?


1
据我所知,除非你让它运行在后台,否则没有任何东西会在后台运行!!! - Teja Nandamuri
3
@T_77有许多Cocoa方法(包括此方法)可以在后台线程上运行代码。 - Rob
1
请问您能告诉我一些 @Rob 的内容吗? - Teja Nandamuri
即使我们没有提供任何后台队列,sendAsynchronousRequest 仍在后台运行... - NSPratik
3
@T_77 所有的NSURLSession方法。地理编码器和位置搜索方法。许多Cocoa方法在后台线程异步执行并带有完成块/闭包。 - Rob
显示剩余2条评论
1个回答

52
不需要使用GCD将其分派到后台队列。实际上,由于完成块在后台线程上运行,相反的情况恰恰是真的,如果您需要在该块中运行任何内容以在主队列上运行(例如,对模型对象进行同步更新,UI更新等),则必须手动将其分派到主队列。例如,假设您要检索结果列表并更新UI以反映此操作,您可能会看到以下内容:
- (void)viewDidLoad 
{
    [super viewDidLoad];

    NSURLSession *session = [NSURLSession sharedSession];

    NSURLSessionDataTask *dataTask = [session dataTaskWithURL:[NSURL URLWithString:@"https://itunes.apple.com/search?term=apple&media=software"] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        // this runs on background thread

        NSError *error;
        NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];

        // detect and handle errors here

        // otherwise proceed with updating model and UI

        dispatch_async(dispatch_get_main_queue(), ^{
            self.searchResults = json[@"results"];    // update model objects on main thread
            [self.tableView reloadData];              // also update UI on main thread
        });

        NSLog(@"%@", json);
    }];

    [dataTask resume];
}

谢谢您的回答,您知道使用URLSessionConfiguration.background时有什么区别吗? - the Reverend
2
@theReverend - 基本上答案是一样的,即会话将异步运行,与您启动它的线程无关,您可以随意从主线程开始它(并确保在完成处理程序中分派代码返回到主队列以更新UI或模型对象)。“后台”在“后台会话”中与队列/线程问题无关,而与应用程序的状态有关(即使应用程序离开前台,它也将继续运行)。 - Rob
1
有时我会收到错误代码1005,连接丢失。 - famfamfam
不确定这一点,因为在 AFHTTPSessionManager 的类似方法 [manager dataTaskWithRequest:...] 中,完成代码可能会在主线程中调用(通过 [NSThread isMainThread] 进行检查)。 - Iulian Nikolaiev
1
是的,我对此非常确定。首先,AFNetworking(和Alamofire)将它们的完成处理程序调度回主队列,这只是为了方便起见。这与OP最初的问题无关。其次,如果您真的想要,甚至可以配置NSURLSession使用主队列。但是,再次强调,这并不重要。这并不改变网络请求是异步的事实。您永远不需要通过GCD分派网络请求的开始,正如OP所提出的那样。 - Rob

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接