【问题标题】:Function can only be called in the main thread, why?函数只能在主线程中调用,为什么?
【发布时间】:2015-09-06 09:18:23
【问题描述】:

在下面的这段代码中,我调用了函数 displayMyAlertMessage() 两次。我调用的第一个工作完美,但第二个给我一个错误,说该函数只能从主线程调用。我该如何在我的情况下做到这一点?

我正在使用此代码:

@IBAction func loginButtonTapped(sender: AnyObject) {
    result2Value = ""
    let userEmail = userEmailTextField.text
    let userPassword = userPasswordTextField.text

    if userPassword.isEmpty || userPassword.isEmpty {
        displayMyAlertMessage("All fields are required")
return;
    }
    //send user data to server side
    let myUrl = NSURL(string: "http://www.avanta.com/extra/test-userLogin.php")
    let request = NSMutableURLRequest(URL:myUrl!)
    request.HTTPMethod = "POST"

    let postString = "email=\(userEmail)&password=\(userPassword)"
    request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)

    let task = NSURLSession.sharedSession().dataTaskWithRequest(request){
        data, response, error in
        if error != nil{
            println("error\(error)")
            return
        }
        var err:NSError?
        var json = NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers, error: &err) as? NSDictionary
        if let parseJSON = json { 
            var resultValue:String = parseJSON["status"] as! String!
            println("result: \(resultValue)")

            if (resultValue == "Success") {
            //login succesful
                NSUserDefaults.standardUserDefaults().setBool(true, forKey: "isUserLogin")
                NSUserDefaults.standardUserDefaults().synchronize()

                self.dismissViewControllerAnimated(true, completion: nil)
               // return
            }
            else{
              self.displayMyAlertMessage("Wrong name or password")
            }
        }
    }
    task.resume()
}

调用这个函数:

func displayMyAlertMessage(userMessage:String){
    var myAlert = UIAlertController(title:"Alert", message:userMessage, preferredStyle: UIAlertControllerStyle.Alert)
    let okAction = UIAlertAction(title:"Ok", style:UIAlertActionStyle.Default, handler:nil)
    myAlert.addAction(okAction)
    self.presentViewController(myAlert, animated:true, completion:nil)
}

我得到的错误:

2015-06-20 14:44:41.646 UserLoginAndRegistration[6064:750474] *** Assertion        failure in -[UIKeyboardTaskQueue waitUntilAllTasksAreFinished],    /SourceCache/UIKit/UIKit-3318.16.14/Keyboard/UIKeyboardTaskQueue.m:374
2015-06-20 14:44:41.657 UserLoginAndRegistration[6064:750474] *** Terminating   app due to uncaught exception 'NSInternalInconsistencyException', reason: '- [UIKeyboardTaskQueue waitUntilAllTasksAreFinished] may only be called from the  main thread.'
*** First throw call stack:
(0x186551e48 0x196c4c0e4 0x186551d08 0x1873d5554 0x18ad2b0a8 0x18ad2b734  0x18ad24a1c 0x18b251564 0x18b0156a8 0x18b0169e4 0x18b0188dc 0x18adee0b4 0x100028f9c 0x10002b500 0x10002b5f4 0x10002b624 0x10002b68c 0x185ee6540 0x187407508 0x187358c94 0x18734861c 0x18740a26c 0x1005a4df0 0x1005af854 0x1005a8120 0x1005b175c 0x1005b2f18 0x19746d2e4 0x19746cfa8)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb) 

【问题讨论】:

  • 您只能从主线程更改 UI,而您正试图从后台线程更改它。
  • @nhgrif 做我想做的事情的正确方法是什么?

标签: function swift error-handling xcode6 lldb


【解决方案1】:

您必须始终从主队列中更新 UI 元素,有时您不这样做时也能正常工作,但大多数时候您的应用程序中出现奇怪的行为,您很幸运编译器警告您,有时需要几天时间才能发现此类错误当事情不起作用时

使用下面的代码调用和关闭您的警报视图

dispatch_async(dispatch_get_main_queue()) {
    self.dismissViewControllerAnimated(true, completion: nil)
} 

dispatch_async(dispatch_get_main_queue()) {
    self.displayMyAlertMessage("Wrong name or password")
}

您可以在Grand Central Dispatch (GCD) Reference查看有关它的更多详细信息

【讨论】:

    【解决方案2】:

    您需要先关闭警报视图。使用下面的代码来执行此操作。

    适用于 Swift 3

    DispatchQueue.main.async {
        your code goes here
    }
    

    【讨论】:

      【解决方案3】:

      您应该将您的进程放入队列中以使其执行。

      你可以参考下面的例子,当我遇到同样的问题时,我是如何在我的场景中解决它的。

      var storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
      var vc: UINavigationController = storyBoard.instantiateViewControllerWithIdentifier("AppViewController") as! UINavigationController
      
      NSOperationQueue.mainQueue().addOperationWithBlock {
          self.presentViewController(vc, animated: true, completion: nil)
          //Above line was generating same exception in my scenario
          // I got it resolved by using NSOperationQueue.mainQueue().addOperationWithBlock {
      }
      

      【讨论】:

        猜你喜欢
        • 2020-02-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-06-18
        • 1970-01-01
        • 2017-11-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多