2015-06-20 24 views
8

W tym kodzie poniżej wywołuję funkcję displayMyAlertMessage() dwa razy. pierwsze, które nazywam, działa idealnie, ale drugie daje mi błąd, mówiąc, że funkcja może być wywołana tylko z głównego wątku. Jak mogę to zrobić w mojej sytuacji?Funkcja może być wywołana tylko w głównym wątku, dlaczego?

Używam tego kodu:

@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() 
} 

Aby wywołać tę funkcję:

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) 
} 

Błąd Dostaję:

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) 
+0

Można jedynie zmienić UI od głównego wątku i starasz się zmienić go z wątku tła. – nhgrif

+0

@nhgrif Jaki jest właściwy sposób robienia tego, co chcę robić? – sdd

Odpowiedz

12

Musisz zawsze aktualizować elementy interfejsu użytkownika od główna kolejka, czasem działa, gdy nie robisz, ale przez większość czasu masz dziwne zachowania w aplikacji, masz szczęście, że kompilator jest ARNING ty, czasami trwać kilka dni, aby znaleźć błędy jak że kiedy rzeczy po prostu nie działają

Użyj kodu poniżej, aby zadzwonić i odwołać alertu widoki

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

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

można zobaczyć więcej szczegółów na ten temat w Grand Central Dispatch (GCD) Reference

+0

Idealne, dziękuję – sdd

+0

@dd Cieszę się, że mogę pomóc, szczęście ze swoją aplikacją! – Icaro

0

Powinieneś umieścić swój proces w kolejce, aby go wykonać.

Możesz odnieść się do poniższego przykładu, w jaki sposób udało mi się go rozwiązać w moim scenariuszu, gdy miałem podobny problem.

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 { 
} 
3

Najpierw należy odrzucić swoje wyświetlenia alertów. Użyj poniższego kodu, aby to zrobić.

Działa z Swift 3

DispatchQueue.main.async { 
    your code goes here 
} 
Powiązane problemy