(Xcode 6 beta / Swift)performSegueWithIdentifier在segue之前有延迟

4

我是第一次学习使用Swift和Xcode 6 beta进行iOS编程。

我正在制作一个简单的测试应用程序,它应该调用API,然后以编程方式转换到不同的视图来呈现检索到的信息。

问题在于转换。 在我的委托方法didReceiveAPIResults中,在成功检索到所有内容之后,我有:

println("--> Perform segue")
performSegueWithIdentifier("segueWhenApiDidFinish", sender: nil)

当应用程序运行时,控制台会输出--> Perform segue,但是在应用实际跳转到下一个视图之前,大约需要5-10秒的延迟时间。在此期间,所有UI组件都被冻结。
我有些困惑,不知道为什么跳转不会立即发生,或者如何调试这个问题!
以下是完整的视图控制器:
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的答案进行了更改,现在已经成功运行。下面是最终实现所需行为的精确代码。我需要将that分配给self,以便在dispatch_async块内访问self。

let that = self

if(NSThread.isMainThread()){
    self.delegate?.didReceiveAPIResults(jsonResult)

}else
{
    dispatch_async(dispatch_get_main_queue()) {
        println(that)
        that.delegate?.didReceiveAPIResults(jsonResult)
    }
}

有趣的是,如果我删除println(that)这一行,代码将无法正常工作!(编译器会报错,提示“找不到成员'didReceiveAPIResults'”)。如果有人能对此进行评论,那就很有意思了...

我认为'println()'编译问题只是Beta版本的副作用之一。我遇到了很多这样奇怪的副作用。毕竟还是Beta版。所以...感谢你的问题。非常有趣。 - nembleton
2个回答

4

我相信在调用时您不在主线程上

self.delegate?.didReceiveAPIResults(jsonResult)

如果您想知道自己是否在主线程上,可以这样做:NSThread.isMainThread()返回一个布尔值。请注意,如果结果显示您不在主线程上,那么您必须是在后台线程上!为什么呢?因为后台线程没有优先级,并且需要很长时间才能看到结果,而主线程是系统的高优先级。 如果要执行以下操作,请在getInfoFromAPI中进行替换...

self.delegate?.didReceiveAPIResults(jsonResult)

使用

dispatch_sync(dispatch_get_main_queue())
{
    self.delegate?.didReceiveAPIResults(jsonResult)
}

在这里,你使用了GCD来获取主队列,并且在主线程的block中执行UI更新。

但要注意,如果你已经在主线程上,调用dispatch_sync(dispatch_get_main_queue())将会永久等待(也就是说,冻结你的应用程序)... 所以请注意这一点。


1
你也可以使用dispatch_async,这样可以避免死锁。 - ahruss
你是指 dispatch_sync 吗? - Ethan
1
不,我的意思是使用dispatch_async而不是dispatch_sync。从主线程调用dispatch_sync(dispatch_get_main_queue(), ...)会导致死锁,而dispatch_async则不会。 - ahruss
是的,但我认为他的问题是因为他在后台线程上,我99%确定。 - Ethan

0

我在使用UITableView的segue时遇到了延迟问题。我已经检查过,似乎是在主线程上运行。在prepareForSegue期间,我检查了“NSThread.isMainThread()”,它总是返回true。

我在Apple Developer论坛上找到了一个解决方案!https://forums.developer.apple.com/thread/5861

这个人说这是iOS 8中的一个bug。

我按照他们的建议,在didSelectRowAtIndexPath中添加了一行代码......Despatch_async.....

对我有用,希望对你也有用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接