问题描述
我刚刚第一次学习Ios编程,使用Swift和Xcode 6 beta。
I'm just learning Ios programming for the first time, with Swift and Xcode 6 beta.
我正在制作一个应该调用API的简单测试应用程序,然后以编程方式segue到不同的视图以显示检索到的信息。
I am making a simple test app that should call an API, and then segue programmatically to a different view to present the information that was retrieved.
问题是segue。在我的委托方法 didReceiveAPIResults
中,在成功检索完所有内容之后,我有:
The problem is the segue. In my delegate method didReceiveAPIResults
, after everything has been successfully retrieved, I have:
println("--> Perform segue")
performSegueWithIdentifier("segueWhenApiDidFinish", sender: nil)
当应用运行时,控制台输出 - >执行segue
,但是在应用程序实际转到下一个视图之前,大约有5-10秒的延迟。在此期间,所有UI组件都被冻结。
When the app runs, the console outputs --> Perform segue
, but then there is about a 5-10 second delay before the app actually segues to the next view. During this time all the UI components are frozen.
我有点陷入困境,想弄清楚为什么segue不会立即发生,或者如何调试这个!
I'm a little stuck trying to figure out why the segue doesn't happen immediately, or how to debug this!
Heres Full View控制器:
Heres The Full View controller:
import UIKit
class ViewController: UIViewController, APIControllerProtocol {
@lazy var api: APIController = APIController(delegate: self)
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func didReceiveAPIResults(results: NSDictionary) {
println(results)
println("--> Perform segue")
performSegueWithIdentifier("segueWhenApiDidFinish", sender: nil)
}
@IBAction func getData(sender : AnyObject){
println("--> Get Data from API")
api.getInfoFromAPI()
}
}
我的API控制器:
import UIKit
import Foundation
protocol APIControllerProtocol {
func didReceiveAPIResults(results: NSDictionary)
}
class APIController: NSObject {
var delegate: APIControllerProtocol?
init(delegate: APIControllerProtocol?) {
self.delegate = delegate
}
func getInfoFromAPI(){
let session = NSURLSession.sharedSession()
let url = NSURL(string: "https://itunes.apple.com/search?term=Bob+Dylan&media=music&entity=album")
let task = session.dataTaskWithURL(url, completionHandler: {data, response, error -> Void in
if(error) {
println("There was a web request error.")
return
}
var err: NSError?
var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions. MutableContainers, error: &err) as NSDictionary
if(err?) {
println("There was a JSON error.")
return
}
self.delegate?.didReceiveAPIResults(jsonResult)
})
task.resume()
}
}
更新:根据Ethan的回答得到了这个工作。以下是最终获得所需行为的确切代码。我需要将
分配给 self
以便在 dispatch_async $ c内访问self $ c>阻止。
UPDATE: Got this working based on Ethan's answer. Below is the exact code that ended up getting the desired behavior. I needed assign that
to self
to have access to self inside the dispatch_async
block.
let that = self
if(NSThread.isMainThread()){
self.delegate?.didReceiveAPIResults(jsonResult)
}else
{
dispatch_async(dispatch_get_main_queue()) {
println(that)
that.delegate?.didReceiveAPIResults(jsonResult)
}
}
有趣的是,这段代码没有如果我删除 println(那)
行就可以了! (构建失败,找不到成员'didReceiveAPIResults'
)。这很奇怪,如果有人可以对此发表评论...
Interestingly, this code does not work if I remove the println(that)
line! (The build fails with could not find member 'didReceiveAPIResults'
). This is very curious, if anyone could comment on this...
推荐答案
我相信你在调用时不在主线程上
I believe you are not on the main thread when calling
self.delegate?.didReceiveAPIResults(jsonResult)
如果你好奇自己是否在主线上,作为练习,你可以做 NSThread.isMainThread()
返回一个bool。
If you ever are curious whether you are on the main thread or not, as an exercise, you can do NSThread.isMainThread()
returns a bool.
无论如何,如果事实证明你不在主线程上,你一定是!为什么?因为后台线程没有优先级,并且在看到结果之前会等待很长时间,这与主线程不同,后者是系统的高优先级。这是做什么...在 getInfoFromAPI
替换
Anyway, if it turns out that you are not on the main thread, you must be! Why? Because background threads are not prioritized and will wait a very long time before you see results, unlike the mainthread, which is high priority for the system. Here is what to do... in getInfoFromAPI
replace
self.delegate?.didReceiveAPIResults(jsonResult)
with
dispatch_sync(dispatch_get_main_queue())
{
self.delegate?.didReceiveAPIResults(jsonResult)
}
在这里,您使用GCD获取主队列并在主线程的块内执行UI更新。
Here you are using GCD to get the main queue and perform the UI update within the block on the main thread.
但要穿,因为如果你已经在主线程上,调用 dispatch_sync(dispatch_get_main_queue())
将会等待FOREVER(又名,冻结你的应用程序)......所以要注意这一点。
But be wear, for if you are already on the main thread, calling dispatch_sync(dispatch_get_main_queue())
will wait FOREVER (aka, freezing your app)... so be aware of that.
这篇关于(Xcode 6 beta / Swift)performSegueWithIdentifier在segue之前有延迟的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!