NSURLSessionDataTask未执行完成处理程序块

9

我正在尝试从我的本地节点服务器拉取一些数据。服务器已经接收到了get请求并记录了下来,但是由于某种原因,我的iOS应用程序不会执行任何在完成处理程序中的代码。以下是代码:

- (IBAction) buttonPressed{
NSURL *url = [NSURL URLWithString:@"http://127.0.0.1:3000/"];
NSURLSessionDataTask *dataTask =
[self.session dataTaskWithURL:url
          completionHandler:^(NSData *data,
                              NSURLResponse *response,
                              NSError *error){
              nameLabel.text = @"yay!";
              /*
              if (!error){
                  nameLabel.text = @"noerr";
                  NSHTTPURLResponse *httpResp = (NSHTTPURLResponse *)response;
                  if (httpResp.statusCode == 200){
                      NSError *jsonErr;

                      NSDictionary *usersJSON =
                      [NSJSONSerialization JSONObjectWithData:data
                                                      options:NSJSONReadingAllowFragments
                                                        error:&jsonErr];

                      if (!jsonErr){
                         // nameLabel.text = usersJSON[@"username"];
                          nameLabel.text = @"nojerr";

                      }
                      else{
                          nameLabel.text = @"jsonErr";
                      }
                  }
              }
              else{
                  nameLabel.text = @"Err";
              }
               */
          }];
[dataTask resume];

当程序运行时,nameLabel并没有改为“yay”。但是,如果我在NSURLSessionDataTask行之前尝试更改nameLabel,它就会改变。

如果以下回答对您有帮助,请选择答案。如果您仍然有相关问题,请随时发表评论。 - wigging
2个回答

14

NSURLSessionDataTask 在后台线程运行。如果您想更新用户界面上的任何内容,例如标签、按钮、表视图等,则必须在主线程上进行操作。如果您想从 completionHandler 块中更新标签文本,则需要在主线程上更新标签,如下所示:

dispatch_sync(dispatch_get_main_queue(), ^{
  nameLabel.text = @"yay!";
});

13

试试这个魔法:

static NSURLSession* sharedSessionMainQueue = nil;
if(!sharedSessionMainQueue){
    sharedSessionMainQueue = [NSURLSession sessionWithConfiguration:nil delegate:nil delegateQueue:[NSOperationQueue mainQueue]];
}

NSURLSessionDataTask *dataTask =
[sharedSessionMainQueue dataTaskWithURL:url completionHandler:^(NSData *data,
                              NSURLResponse *response,
                              NSError *error){
    //now will be on main thread
}];
[dataTask resume];

这样可以给你原始的NSURLConnection行为,使用主线程上的完成处理程序,因此您可以安全地更新用户界面。但是,假设您想要解析下载或进行一些重型处理,在那种情况下,您可能会从操作队列的后台线程中的完成处理程序受益,然后使用dispatch_sync作为最后一步切换到主线程。


2
+1 - 这是一种更好的方式,因为您可以选择在后台线程上运行其他任务,并假设所有内容都在主线程上运行。 - Jonathan King
嗯,Jonathon如果你使用这种方法,完成块中的所有内容都将(只能)在主线程上。 - Fattie
Joe的意思是,如果需要的话,从主线程完成块中创建后台线程。 - malhal

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