(Xcode 6 beta / Swift) performSegueWithIdentifier has delay before segue

可紊 提交于 2019-12-31 00:50:05

问题


I'm just learning Ios programming for the first time, with Swift and Xcode 6 beta.

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.

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)

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.

I'm a little stuck trying to figure out why the segue doesn't happen immediately, or how to debug this!

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

    }
}

And my API controller:

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


    }    
}

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

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...


回答1:


I believe you are not on the main thread when calling

self.delegate?.didReceiveAPIResults(jsonResult)

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.

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

Here you are using GCD to get the main queue and perform the UI update within the block on the main thread.

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.




回答2:


I have a delay problem with segue from a UITableView. I have checked and I appear to be on the main thread. I checked "NSThread.isMainThread()" during prepareForSegue. It always returns true.

I found a solution on Apple Developer forums! https://forums.developer.apple.com/thread/5861

This person says it is a bug in iOS 8.

I followed their suggestion to add a line of code to didSelectRowAtIndexPath...... Despatch_async.....

It worked for me, hopefully you too.



来源:https://stackoverflow.com/questions/25007045/xcode-6-beta-swift-performseguewithidentifier-has-delay-before-segue

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!