在开发一些涉及网络访问的 app 时,我们通常的逻辑是将耗时网络操作放在新起的线程中去做,让在主线程中执行的方法尽快返回,否则前台视图就会处于假死状态。等后台线程的网络访问结束时再去更新前台视图。不过这样的逻辑在iOS开发中遇到了问题。
我的 app 需要用户登陆,当用户点击登陆按钮后我新起一个线程去服务器验证,验证成功后跳转到新的视图。如下:
【点击登陆按钮】→【新起线程访问服务器】→【成功后跳转视图】
跳转视图的代码:
[self.navigationController pushViewController:shakeViewCtr animated:YES];
我用的是导航控制器,shakeViewCtr 是将要跳转到的视图,然后程序崩溃,控制台出现如下错误提示:
Tried to obtain the web lock from a thread other than the main thread or the web thread. This may be a result of calling to UIKit from a secondary thread. Crashing now...
提示说是因为在副线程中调用了 UIKIT 的方法,UIKIT 是 iOS 的 UI 框架。这就意味着在非主线程中不能更改前台视图。
别急,苹果还有这样的机制来处理,可以在副线程中通知主线程去更改前台视图。
将更新视图的代码用一个方法(loginSuccess)来封装,副线程中完成网络访问后使用 performSelectorOnMainThread:withObject:waitUntilDone 方法来通知主线程执行loginSuccess 方法。部分代码如下:
[self performSelectorOnMainThread:@selector(loginSuccess) withObject:nil waitUntilDone:NO];
- (void)loginSuccess {
[self.navigationController pushViewController:shakeViewCtr animated:YES];
}
那么,现在的流程是:
【点击登陆按钮】→【新起线程访问服务器】→【成功后通知主线程跳转视图】
参考:http://zyc-to.blog.163.com/blog/static/171524002011997143682/