我使用NSURLSession向服务器发出请求。为此,我使用自定义completionHandler创建NSURLSessionTask。
根据结果我想切换到另一个视图。但是,当我在完成处理程序中执行此操作时,它不起作用。该应用程序崩溃并出现以下错误:
NSInternalInconsistencyException
完整错误描述如下:
*** Assertion failure in -[UIKeyboardTaskQueue waitUntilAllTasksAreFinished], /SourceCache/UIKit_Sim/UIKit-3302.3.1/Keyboard/UIKeyboardTaskQueue.m:374
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[UIKeyboardTaskQueue waitUntilAllTasksAreFinished] may only be called from the main thread.'
注意:要更改视图,请使用以下代码
let vc: AnyObject! = self.storyboard?.instantiateViewControllerWithIdentifier(viewID)
self.showViewController(vc as UIViewController, sender: vc)
这里有什么问题?
答案 0 :(得分:10)
主要问题是您的错误消息是报告“...可能只能从主线程调用”。因此,您可能已经在后台线程中调用了此代码(可能是网络请求的完成块或类似的东西)。所以你必须将这段代码发送回主队列:
dispatch_async(dispatch_get_main_queue()) {
let vc = self.storyboard.instantiateViewControllerWithIdentifier(viewID) as UIViewController
showViewController(vc, sender: self)
}
请注意,此代码段会进行一些次要的,无关的更改,即:
将目标视图控制器指定为自己的发件人是没有意义的。通常,您将使用当前视图控制器或某些UIKit控件作为sender
。
我将self
指定为sender
,因为我认为您是在源视图控制器中执行此操作。或者,如果这个按钮位于IBAction
,您可能会使用sender
本身的IBAction
参数,而不是源视图控制器。
我会失去AnyObject
演员。我知道编译器可能会建议你,但它没有帮助代码的易读性。我建议直接将其投放到UIViewController
。
答案 1 :(得分:1)
您执行的任何影响用户界面的操作都必须在主线程上运行,而不是在完成处理程序中运行。因此,在您的完成处理程序中,调用performSelectorOnMainThread或使用其他一种允许您将该调用放到主线程上的机制。