ios 在主线程上运行 NSURLSession 完成处理程序
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20052682/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Running NSURLSession completion handler on main thread
提问by otter
I am using a NSURLSession to get the values to populate a TableView. I am updating the TableView in the completion handler, but using [[NSThread currentThread] isMainThread]
has shown me that the completion handler isn't running in the main thread. Since I should only updating the UI from the main thread, I know this isn't correct. Is there a way to trigger an action on the main thread from the completion handler? Or is using a NSURLSession the wrong way to go about this?
我正在使用 NSURLSession 来获取填充 TableView 的值。我正在更新完成处理程序中的 TableView,但使用[[NSThread currentThread] isMainThread]
表明完成处理程序没有在主线程中运行。由于我应该只从主线程更新 UI,我知道这是不正确的。有没有办法从完成处理程序触发主线程上的操作?或者使用 NSURLSession 是错误的方法吗?
NSURLSession *session = [NSURLSession sharedSession];
[[session dataTaskWithURL:[NSURL URLWithString:@"http://myurl"]
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSError *jsonError = nil;
NSArray* jsonUsers = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
if (jsonError) {
NSLog(@"error is %@", [jsonError localizedDescription]);
// Handle Error and return
return;
}
self.userArray = jsonUsers;
[self.userTableView reloadData];
if ([[NSThread currentThread] isMainThread]){
NSLog(@"In main thread--completion handler");
}
else{
NSLog(@"Not in main thread--completion handler");
}
}] resume];
回答by graver
Yes, just dispatch your main thread stuff using GCD
:
是的,只需使用GCD
以下命令调度您的主线程内容:
NSURLSession *session = [NSURLSession sharedSession];
[[session dataTaskWithURL:[NSURL URLWithString:@"http://myurl"]
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSError *jsonError = nil;
NSArray* jsonUsers = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
if (jsonError) {
NSLog(@"error is %@", [jsonError localizedDescription]);
// Handle Error and return
return;
}
dispatch_async(dispatch_get_main_queue(), ^{
self.userArray = jsonUsers;
[self.userTableView reloadData];
if ([[NSThread currentThread] isMainThread]){
NSLog(@"In main thread--completion handler");
}
else{
NSLog(@"Not in main thread--completion handler");
}
});
}] resume];
回答by bugloaf
@graver's answer is good. Here's another way you can do it:
@graver 的回答很好。这是您可以执行的另一种方法:
NSURLSession* session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]
delegate:nil
delegateQueue:[NSOperationQueue mainQueue]];
[[session dataTaskWithURL:[NSURL URLWithString:@"http://myurl"]
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSError *jsonError = nil;
NSArray* jsonUsers = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
if (jsonError) {
NSLog(@"error is %@", [jsonError localizedDescription]);
// Handle Error and return
return;
}
self.userArray = jsonUsers;
[self.userTableView reloadData];
if ([[NSThread currentThread] isMainThread]){
NSLog(@"In main thread--completion handler");
}
else{
NSLog(@"Not in main thread--completion handler");
}
}] resume];
This way you create a session that calls the completion block and any delegate methods on the main thread. You may find this more aesthetically pleasing, but you do lose the advantage of running the "hard work" in the background.
通过这种方式,您可以创建一个会话,该会话在主线程上调用完成块和任何委托方法。您可能会发现这在美学上更令人愉悦,但您确实失去了在后台运行“艰苦工作”的优势。
回答by Adnan Aftab
Here is the best way to update UI from blocks and completion handler, and also when you not confrim which thread running your code.
这是从块和完成处理程序更新 UI 的最佳方法,也是当您不确认哪个线程运行您的代码时。
static void runOnMainThread(void (^block)(void))
{
if (!block) return;
if ( [[NSThread currentThread] isMainThread] ) {
block();
} else {
dispatch_async(dispatch_get_main_queue(), block);
}
}
This is static method which will have a block, and will run on main thread, it will act like a
这是一个静态方法,它将有一个块,并将在主线程上运行,它将像一个
runOnMainThread(^{
// do things here, it will run on main thread, like updating UI
});
回答by Big-O Claire
You can try this:
你可以试试这个:
[self.userTableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO];
回答by SPA
send a notification on completion that will be observed by the table view controller which will then do a reloadData;
发送完成通知,表视图控制器将观察到该通知,然后执行 reloadData;
this has the advantage that if you later move this download code off to a separate class, e.g. a model object, then no changes are required and also the code can be reused in other projects without making changes
这样做的好处是,如果您稍后将此下载代码移至单独的类,例如模型对象,则不需要更改,并且代码可以在其他项目中重用而无需进行更改
回答by William Hu
Swift 3.1
斯威夫特 3.1
DispatchQueue.main.async {
tableView.reloadData()
}