xcode 在 restful 回调 (swift) 上呈现 segue
xcode present segue on restful callback (swift)
我是自学成才的 Swift 用户,我尝试做一些简单的事情,但这让我很困惑。我有一个简单的注册表。提交项目注册后,我想通过 segue 将页面移动到 "how it works" 页面,但只有当我的 restful API returns 成功时。到目前为止,这是我所拥有的;也请随时给我一个更好的方法来做到这一点。欢迎所有批评。
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
的 segue 附加到此视图控制器,将转到 HowItWorksViewController
。我从 Xcode:
收到这个错误
2015-10-12 21:22:43.261 ZiftDine[11396:2307755] Assertion failure in -[UIKeyboardTaskQueue waitUntilAllTasksAreFinished], /SourceCache/UIKit_Sim/UIKit-3347.44.2/Keyboard/UIKeyboardTaskQueue.m:374
2015-10-12 21:22:43.391 ZiftDine[11396:2307755] Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[UIKeyboardTaskQueue waitUntilAllTasksAreFinished] may only be called from the main thread.'
任何用 UI 完成的事情都应该在主线程上完成,尝试像这样包装你的 performSegue 调用:
dispatch_async(dispatch_get_main_queue(),{
self.performSegueWithIdentifier("howItWorksSegue", sender: self)
})
@Swinny89 给出了您问题的解决方案,但需要一些解释。
如果您阅读了 dataTaskWithRequest:completionHandler:
的描述,这是您正在使用的方法(尽管您的 Swift 代码使用尾随闭包语法删除 completionHandler
标签并放置闭包在括号外)它说:
completionHandler: The completion handler to call when the load
request is complete. This handler is executed on the delegate queue.
然后如果你阅读 init 方法的描述 sessionWithConfiguration:delegate:delegateQueue:
它说:
queue: A queue for scheduling the delegate calls and completion
handlers. If nil, the session creates a serial operation queue for
performing all delegate method calls and completion handler calls.
不同线程上的串行操作队列 运行。
因此,综合所有这些信息,这意味着您的完成闭包将在主线程以外的线程上执行。
iOS/Mac 开发的一个基本规则是您必须从主线程执行所有 UI 调用。如果通话改变了屏幕上的任何内容,则为 UI 通话。
您的代码正在从后台线程调用 performSegueWithIdentifier:
。它会更改屏幕上显示的内容,因此它必须是 UI 调用。因此它需要在主线程上 运行。
GCD 函数 dispatch_async()
,队列 dispatch_get_main_queue()
,提交一个闭包到主调度队列 运行,运行 的队列主线程。
所以 Swinny 的解决方案解决了您的问题。
这里的要点:
任何时候你在闭包中 运行 宁代码,停下来思考:"Am I positive that this closure will always be run on the main thread?" 如果答案是否定的,将代码包含在对 dispatch_async(dispatch_get_main_queue()
的调用中,就像 Swinny 的回答。
@Duncan C 和@Swinny89 的回答很好。对于来自 Google 的任何人,Swift 3 中的语法略有变化:
DispatchQueue.main.async(execute: {
self.performSegueWithIdentifier("howItWorksSegue", sender: self)
})
我是自学成才的 Swift 用户,我尝试做一些简单的事情,但这让我很困惑。我有一个简单的注册表。提交项目注册后,我想通过 segue 将页面移动到 "how it works" 页面,但只有当我的 restful API returns 成功时。到目前为止,这是我所拥有的;也请随时给我一个更好的方法来做到这一点。欢迎所有批评。
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
的 segue 附加到此视图控制器,将转到 HowItWorksViewController
。我从 Xcode:
2015-10-12 21:22:43.261 ZiftDine[11396:2307755] Assertion failure in -[UIKeyboardTaskQueue waitUntilAllTasksAreFinished], /SourceCache/UIKit_Sim/UIKit-3347.44.2/Keyboard/UIKeyboardTaskQueue.m:374
2015-10-12 21:22:43.391 ZiftDine[11396:2307755] Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[UIKeyboardTaskQueue waitUntilAllTasksAreFinished] may only be called from the main thread.'
任何用 UI 完成的事情都应该在主线程上完成,尝试像这样包装你的 performSegue 调用:
dispatch_async(dispatch_get_main_queue(),{
self.performSegueWithIdentifier("howItWorksSegue", sender: self)
})
@Swinny89 给出了您问题的解决方案,但需要一些解释。
如果您阅读了 dataTaskWithRequest:completionHandler:
的描述,这是您正在使用的方法(尽管您的 Swift 代码使用尾随闭包语法删除 completionHandler
标签并放置闭包在括号外)它说:
completionHandler: The completion handler to call when the load request is complete. This handler is executed on the delegate queue.
然后如果你阅读 init 方法的描述 sessionWithConfiguration:delegate:delegateQueue:
它说:
queue: A queue for scheduling the delegate calls and completion handlers. If nil, the session creates a serial operation queue for performing all delegate method calls and completion handler calls.
不同线程上的串行操作队列 运行。
因此,综合所有这些信息,这意味着您的完成闭包将在主线程以外的线程上执行。
iOS/Mac 开发的一个基本规则是您必须从主线程执行所有 UI 调用。如果通话改变了屏幕上的任何内容,则为 UI 通话。
您的代码正在从后台线程调用 performSegueWithIdentifier:
。它会更改屏幕上显示的内容,因此它必须是 UI 调用。因此它需要在主线程上 运行。
GCD 函数 dispatch_async()
,队列 dispatch_get_main_queue()
,提交一个闭包到主调度队列 运行,运行 的队列主线程。
所以 Swinny 的解决方案解决了您的问题。
这里的要点:
任何时候你在闭包中 运行 宁代码,停下来思考:"Am I positive that this closure will always be run on the main thread?" 如果答案是否定的,将代码包含在对 dispatch_async(dispatch_get_main_queue()
的调用中,就像 Swinny 的回答。
@Duncan C 和@Swinny89 的回答很好。对于来自 Google 的任何人,Swift 3 中的语法略有变化:
DispatchQueue.main.async(execute: {
self.performSegueWithIdentifier("howItWorksSegue", sender: self)
})