使用 performSegueWithIdentifier Swift 2.1 时出错

Error using performSegueWithIdentifier Swift 2.1

我正在尝试使用 "performSegueWithIdentifier" 以编程方式制作 Segue,但由于某种原因它无法正常工作。我要 post 我的代码,因为它真的很简单,但它显示了一个奇怪的错误。

这是我的代码:

import UIKit

class LoginViewController: UIViewController {

@IBOutlet weak var login: UIButton!

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

@IBAction func loginButtonPressed(sender: UIButton) {

    if (((user.text) != "") && ((password.text) != ""))
    {
        let request = NSMutableURLRequest(URL: NSURL(string: "http://website.com/login.php")!)
        request.HTTPMethod = "POST"
        let postString = "user="+user.text!+"&password="+password.text!

        request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
        let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
            data, response, error in

            if error != nil
            {
                print(error)
                return
            }

            let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)!

            if (responseString=="Correct")
            {
                self.performSegueWithIdentifier("loginSegue", sender: sender)
            }
            else
            {

            }

        }
        task.resume()
    }
    else
    {

    }
}

我已经创建了一个从我的 LoginViewController 到 ID "loginSegue" 的 NavigationController 的 Segue,但它仍然无法正常工作。

我的代码有什么问题?

这是 Xcode 的错误:

2015-11-23 21:09:43.224 App[5511:3896125] *** Assertion failure in -       [UIKeyboardTaskQueue waitUntilAllTasksAreFinished], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit/UIKit-3512.29.5/Keyboard/UIKeyboardTaskQueue.m:378
2015-11-23 21:09:43.226 App[5511:3896125] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[UIKeyboardTaskQueue waitUntilAllTasksAreFinished] may only be called from the main thread.'
*** First throw call stack:
(0x2232985b 0x33c9edff 0x22329731 0x230baddb 0x2648a5fd 0x2648aeaf 0x2648483b 0x26aa2321 0x265f2b23 0x267c44e7 0x267c5e55 0x267c81e5 0x267c8451 0x26556367 0x267cb6e7 0x267cb735 0x267dfb99 0x267cb65b 0x26a6e6b9 0x26b45919 0x26b45747 0x267bd87d 0x72fd0 0x71b0c 0x6e560 0x21b505b5 0x21b5fcd7 0x230e856d 0x23049fdf 0x2303c3cf 0x230ea82d 0x11e461b 0x11dcf53 0x11e5b0f 0x11e5961 0x34558e0d 0x345589fc)
libc++abi.dylib: terminating with uncaught exception of type NSException

对此最 "simple" 的修复可能是将对 self.performSegueWithIdentifier("loginSegue", sender: sender) 的调用包装在主线程的 dispatch_async 中,但是,很可能还有其他方法我们无法在此处看到的目标控制器代码问题。

问题很可能是 NSURLSessiondelegateQueue 不是主队列,而且 [UIKeyboardTaskQueue waitUntilAllTasksAreFinished] 在那个线程的某处被调用,但它只能是在主线程上调用。

NSURLSession 的完成块在会话的委托队列上调用,除非您另有指定,否则在后台线程上 运行。

您不应从后台线程调用任何 UI 代码(几乎是整个 UIKit)。有时它可以工作,有时它什么都不做,有时它会崩溃。别这样。

因此你不能在这些完成块中执行 任何 UI 代码,除非你将该代码发送到主线程,正如 Dan 在他的回答中所说。

更改后的代码可能如下所示:

    let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
        data, response, error in
        if error != nil
        {
            print(error)
            return
        }
        let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)!

        if (responseString=="Correct")
        {
            //Use dispatch_async to do the performSegueWithIdentifier
            //on the main thread.
            dispatch_async(dispatch_get_main_queue())
            {
              self.performSegueWithIdentifier("loginSegue", sender: sender)
            }
        }
        else
        {
        }
    }