我是自学Swift用户并试图做一些简单的事情,但它让我很难过。我有一个简单的登记表。在提交注册项目后,我想通过segue将页面移动到“如何工作”页面,但仅当我的restful API返回成功时。这是我到目前为止所拥有的;随时给我一个更好的方法来做这件事。所有的批评都是受欢迎的。
df = sns.load_dataset("df")
g = sns.FacetGrid(df)
g.map(s.skdeplot, "df.columns");
我有一个名为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()
的segue附加到此视图控制器,转到howItWorksSegue
。我从Xcode收到此错误:
2015-10-12 21:22:43.261 ZiftDine [11396:2307755]断言失败 - [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]只能从主线程中调用。'
答案 0 :(得分:7)
使用UI完成的任何操作都应该在主线程上完成,尝试将performSegue调用包装成这样:
dispatch_async(dispatch_get_main_queue(),{
self.performSegueWithIdentifier("howItWorksSegue", sender: self)
})
答案 1 :(得分:1)
@ Swinny89为您的问题提供了解决方案,但有些解释是有条理的。
如果您阅读了dataTaskWithRequest:completionHandler:
的描述,这是您正在使用的方法(尽管您的Swift代码使用尾随闭包语法删除completionHandler
标签并将闭包放在括号之外)它说:
completionHandler:加载时调用的完成处理程序 请求已完成。此处理程序在委托队列上执行。
然后,如果你阅读了init方法sessionWithConfiguration:delegate:delegateQueue:
的描述,那就说:
queue:用于调度委托调用和完成的队列 处理程序。如果为nil,则会话为其创建一个串行操作队列 执行所有委托方法调用和完成处理程序调用。
串行操作队列在不同的线程上运行。
因此,将所有这些信息放在一起,就意味着你的完成闭包将在主线程以外的线程上执行。
iOS / Mac开发的基本规则是您必须从主线程执行所有UI调用。如果一个呼叫改变了屏幕上的任何内容,那就是一个UI呼叫。
您的代码正在从后台线程调用performSegueWithIdentifier:
。它会更改屏幕上显示的内容,因此必须是UI调用。因此,它需要在主线程上运行。
队列为dispatch_async()
的GCD函数dispatch_get_main_queue()
提交一个在主调度队列上运行的闭包,一个在主线程上运行的队列。
所以Swinny的解决方案可以解决您的问题。
这里的外卖:
每当你在一个闭包中运行代码时,请停下来思考:“我是否肯定这个闭包将始终在主线程上运行?”如果答案是否定的,请将代码包含在dispatch_async(dispatch_get_main_queue()
的调用中,就像Swinny的回答一样。
答案 2 :(得分:0)
@Duncan C和@ Swinny89的答案都很好。对于任何从谷歌进来的人来说,Swift 3中的语法有所改变:
DispatchQueue.main.async(execute: {
self.performSegueWithIdentifier("howItWorksSegue", sender: self)
})