2015-10-13 3 views
1

Я самолюбивый пользователь Swift и пытаюсь сделать что-то простое, но у меня все в порядке. У меня простая форма регистрации. После отправки элементов для регистрации я хочу переместить страницу на страницу «как это работает» через segue, но ТОЛЬКО, когда мой успокаивающий API возвращает успех. Вот что я до сих пор; не стесняйтесь присылать мне лучший способ сделать это. Все критические замечания приветствуются.xcode present segue on restful callback (swift)

let myUrl = NSURL(string:"http://www.example.com/scripts/Register.php") 
let request = NSMutableURLRequest(URL: myUrl!) 
request.HTTPMethod = "POST" 

let postString = "email=\(email)&password=\(pass)" 
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 
    var showTutorial : Bool = false 

    if let parseJSON = json { 
     var returnValue = parseJSON["status"] as? String 
     println("Status: \(returnValue)") 

     var isUserRegistered: Bool = false 
     if (returnValue == "Success") { 
      showTutorial = true 
     } else if (returnValue == "Error") {      
      // handle error 
     } 
    } 

    // if successful registration, show how it works page 
    if (showTutorial) { 
     self.performSegueWithIdentifier("howItWorksSegue", sender: self) 
    } 
} 
task.resume() 

У меня есть переход по имени howItWorksSegue прилагается к этой точке зрения контроллера происходит в HowItWorksViewController. Я получаю эту ошибку с Xcode:

2015-10-12 21: 22: 43.261 ZiftDine [11396: 2307755] отказ Assertion в - [UIKeyboardTaskQueue waitUntilAllTasksAreFinished], /SourceCache/UIKit_Sim/UIKit-3347.44.2 /Keyboard/UIKeyboardTaskQueue.m:374
2015-10-12 21: 22: 43.391 ZiftDine [11396: 2307755] Завершение приложения из-за неотображенного исключения «NSInternalInconsistencyException», причина: '- [UIKeyboardTaskQueue waitUntilAllTasksAreFinished] может вызываться только из основной поток. '

ответ

7

Все, что делается с UI должно быть сделано в основном потоке, попробуйте упаковка вас performSegue называют так:

dispatch_async(dispatch_get_main_queue(),{ 
    self.performSegueWithIdentifier("howItWorksSegue", sender: self) 
}) 
+0

Спасибо. Я просто попробовал, и это сработало. Все еще интересно, если это хороший метод для этого. –

+0

Это точно правильный метод для этого :) Я использую его очень часто. Если он ответил на ваш вопрос, пожалуйста, отметьте как ответ – Swinny89

+3

@KJBonds Если этот ответ решил проблему, вы должны отметить ее как принятую. –

1

@ Swinny89 дал решение вашей проблемы, но какое-то объяснение в порядке.

Если вы читали описание dataTaskWithRequest:completionHandler:, который является методом, который вы используете (хотя ваш Swift код использует трейлинг синтаксис закрытия уронить completionHandler ярлык и положить закрытия вне скобок) он говорит:

completeHandler: обработчик завершения вызова, когда запрос на загрузку завершен. Этот обработчик выполняется в очереди делегатов.

Тогда, если вы читаете описание метода инициализации sessionWithConfiguration:delegate:delegateQueue: он говорит:

очередь: Очередь для планирования делегата вызовов и завершения обработчиков. Если nil, сеанс создает очередь последовательных операций для , выполняющую все вызовы метода делегата и вызовы обработчика завершения.

Серийные очереди работы работают по другой теме.

Таким образом, объединяя все эти фрагменты информации, это означает, что ваше завершение закрытия будет выполнено по нитке, отличной от основной нити.

Основным правилом разработки iOS/Mac является то, что вы должны выполнять все вызовы пользовательского интерфейса из основного потока. Если вызов меняет что-либо на экране, это вызов пользовательского интерфейса.

Ваш код вызывает performSegueWithIdentifier: из фоновой темы. Он изменяет то, что отображается на экране, поэтому это должен быть вызов пользовательского интерфейса. Поэтому его нужно запускать на основном потоке.

Функция GCD dispatch_async(), с очередью dispatch_get_main_queue(), представляет закрытие, которое должно быть запущено в основной диспетчерской очереди, очередь, которая запускается в основном потоке.

So Решение Swinny устраняет вашу проблему.

отводящий здесь:

Каждый раз, когда вы работаете код в затворе, остановиться и подумать: «Могу ли я уверен, что это замыкание всегда будет работать на главном потоке» Если ответ отрицательный, приложите код к вызову dispatch_async(dispatch_get_main_queue(), как ответ Swinny.

0

Ответы @Duncan C и @ Swinny89 хорошие. Для всех, кто пришел из Google, синтаксис в Swift 3 немного изменился:

DispatchQueue.main.async(execute: { 
    self.performSegueWithIdentifier("howItWorksSegue", sender: self) 
})