延迟对NSURLSession反应的反应

时间:2015-09-30 18:30:00

标签: ios swift

我的Swift应用程序出现了一个奇怪的问题,其中看似连续的事件序列导致无关紧要的输出。我有一个按钮单击操作,如下所示(其中self.indicator是UIActivityIndi​​catorView,self.errorBox是UILabel):

func onSigninClick(sender: UIButton!) {

    let url = NSURL_REMOVED_FROM_EXAMPLE
    var request = NSMutableURLRequest(URL: url!)
    request.HTTPMethod = "POST"

    request.addValue("application/json", forHTTPHeaderField: "Content-Type")
    request.addValue("application/json", forHTTPHeaderField: "Accept")

    var data = [
        "u": self.usernameBox.text,
        "p": self.passwordBox.text
    ]
    var err: NSError?
    request.HTTPBody = NSJSONSerialization.dataWithJSONObject(data, options: nil, error: &err)

    let config = NSURLSessionConfiguration.defaultSessionConfiguration()
    let session = NSURLSession(configuration: config)

    UIApplication.sharedApplication().networkActivityIndicatorVisible = true
    self.indicator.startAnimating()
    self.errorBox.text = ""

    session.dataTaskWithRequest(request, completionHandler: {
        (data, response, error) in

        self.indicator.stopAnimating()
        UIApplication.sharedApplication().networkActivityIndicatorVisible = false

        if error != nil {
            Logger.warn("Sign In Error: \(error.localizedDescription)")
        } else {
            let json = Parser.parseJson(data) // returns SwiftyJSON object
            Logger.info("Received response: \(json.stringValue)")
            if json["result"].boolValue {
                // success
                self.dismissViewControllerAnimated(true, completion: nil)
                NSNotificationCenter.defaultCenter().postNotificationName(Account.loginNotification, object: self)
            } else {
                // additional errors within message
                for error in json["errors"]["details"].arrayValue {
                    let code = error["code"].intValue
                    let message = error["message"].stringValue
                    Logger.error("Internal error \(code): \(message)")

                    if code == 1001 {
                        self.errorBox.text = "You must specify username and password"
                    } else if code == 1002 {
                        self.errorBox.text = "Incorrect username or password"
                    } else {
                        self.errorBox.text = "Unknown error, error code: \(code)"
                    }
                }
            }
        }
    }).resume()
}

我发送请求并收到回复。发送请求时,会出现旋转指示符,并且一旦收到消息,其意图就是消失。

问题在于,请求会在UI"做出反应之前使其恢复正常。它。在上面的逻辑中,您可以看到日志消息。消息一出现在日志中,我也会看到UIApplication.sharedApplication().networkActivityIndicatorVisible图标消失。然而,指示器(被告知之前停止动画)继续旋转另外5秒左右。同样适用于错误消息,该消息仅在约5秒后出​​现。我在loadView中也定义了self.indicator.hidesWhenStopped = true

我无法弄清楚发生了什么。为什么指示器和错误框都不会更新到更晚?即使重绘是异步的,也不应该花5秒钟。

另外,我尝试计时,延迟似乎也有所不同。有时5秒,有时长达30秒。

1 个答案:

答案 0 :(得分:2)

dataWithRequest:completionHandler:方法提供的完成处理程序将在delegateQueue的{​​{1}}上调用。默认情况下,此队列是为NSURLSession创建的序列NSOperationQueue,即不是主线程。即使这样,我也不确定iOS是否为在主线程之外启动的UI更新提供了任何行为保证。

在iOS中,UI操作必须在主线程上进行。当你告诉你的活动指示器停止动画时,在主线程注意到更新之前不会发生任何事情。

尝试将NSURLSession的{​​{1}}设置为主要队列,或者您也可以尝试使用delegateQueue到主线程以获取UI更新:

NSURLSession

修改显示dispatch_async方法:

虽然self.indicator.stopAnimating() UIApplication.sharedApplication().networkActivityIndicatorVisible = false 属性是只读的,但您可以在使用专门的init方法创建delegateQueue时设置它:

delegateQueue