完成 URLRequest 后的计时问题

timing issue after completion of URLRequest

我有一个我无法解决的行为。 我有一个控制器(控制器 1),我在其中检查一些默认值。如果不存在(第一次使用应用程序:检查登录名和密码)我提供(模态)设置 vc:

IN CONTROLLER 1
override func viewDidAppear(_ animated: Bool) {
    if(!isKeyPresentInUserDefaults(key: "username")) {
        NSLog("username not present")
        let vc = self.storyboard?.instantiateViewController(withIdentifier: "settings") as! SettingsViewController
        self.present(vc, animated: true, completion: nil)
    }
}

在这个 vc(控制器 2)(也在主故事板中)中,我完成了一个按钮。按下时,它关联到:

IN CONTROLLER 2: SettingsVc -> ID : settings
@IBAction func doneSettings(sender: AnyObject) {
    if(isInternetAvailable()) {
        NSLog("internet available")

         login { (result) in
         switch result
         {
         case .Success(let result):
            //print(result)
            self.dismissSelf()
         break

         case .Failure(let error):
            print(error)
         break
         }
         }
     }
    else {
        NSLog("internet not available")
    }
}

dismissSelf 函数在设置vc中定义为:

func dismissSelf() {
    NSLog("dismissSettingsVC")
    self.dismiss(animated: false, completion: nil)
}

登录函数在另一个 class 中定义,处理网络内容并且按原样:

func login(completion: @escaping (AsyncResult<[CustomUserObject]>)->())
{
    let myUrl = URL(string: "http://www.xxxx.com/api/api.php");
    var request = URLRequest(url:myUrl!)
    request.httpMethod = "POST"// Compose a query string
    let postString = "u=login&s=password&cmd=login";
    request.httpBody = postString.data(using: String.Encoding.utf8);

    let session = URLSession.shared
    let task = session.dataTask(with: request as URLRequest){
        (data, response, error) -> Void in
        if let error = error
        {
            completion(AsyncResult.Failure(error as NSError?))
        } else {
            let result: [CustomUserObject] = []//deserialization json data into array of [CustomUserObject]
            let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)
            print("*********response data = \(responseString)")
            completion(AsyncResult.Success(result))
        }
    }
    task.resume()
}

所以,我第一次启动应用程序(默认没有登录,没有密码),然后出现设置vc。我按下带有硬编码参数的完成按钮。登录被正确调用,我正确收到答案,完成后我应该关闭设置 vc。 事情是,我看到 NSLOG 解雇,但解雇出现在网络功能完成后几秒钟(从 10 秒到最多一分钟),我无法理解。为什么会有这样的延迟?有什么想法吗?

2017-11-27 21:54:33.262892 app[998:211517] username not present
2017-11-27 21:54:36.119754 app[998:211517] internet available
*********response data = 
Optional({"cmd":"login","success":"true","message":"login succeded"})
2017-11-27 21:54:38.472306 app[998:211542] dismissSettingsVC
2017-11-27 21:54:48.048095 app[998:211517] username not present

在这种情况下,在收到登录结果后需要 10 秒才能关闭设置vc。

另一个:

2017-11-27 22:04:20.364097 app[998:211517] internet available
*********response data = 
Optional({"cmd":"login","success":"true","message":"login succeded"})
2017-11-27 22:04:22.495642 app[998:212974] dismissSettingsVC
2017-11-27 22:05:00.049177 app[998:211517] username not present

在另一种情况下,在收到登录结果后需要 38 秒才能关闭设置vc。

已编辑 我尝试不使用 vc 呈现。相反,在控制器 1 中,我添加了一个视图,如果默认用户名不存在,我首先将其设置为可见,然后我将在登录完成后隐藏。在此视图中,我添加了一个按钮来调用 loginAction。

@IBAction func loginAction(sender: AnyObject) {
    if(isInternetAvailable()) {
        NSLog("internet available")

        login { (result) in
            switch result
            {
            case .Success(let users):
                print(users)
                self.loginView.isHidden = true
                NSLog("login ok: hiding view")
                break
            case .Failure(let error):
                print(error ?? "ERROR")
                break
            }
        }

    }
    else {
        NSLog("internet not available")
    }
}

同样的结果:

我看到完成和收到的数据:

2017-11-28 18:17:34.314706 cellar[1270:311710] username not present
2017-11-28 18:17:35.066333 cellar[1270:311710] internet available
2017-11-28 18:17:35.076930 cellar[1270:311710] done login
Optional({"cmd":"login","success":"true","message":"login succeded"})
2017-11-28 18:17:37.655829 cellar[1270:311763] login ok: hiding view

视图应该隐藏在 NSLOG 之前 "login ok: hiding view"。相反,UI 在(大约一分钟,但可变)

后几秒更新

如果我等待网络内容完成以执行 UI 更新,什么可以避免 UI 被更新?

更新: 奇怪的情况: 一旦我得到网络完成结果,通过改变方向,解雇马上出现:

Optional({"cmd":"login","success":"true","message":"login succeded"})
2017-11-28 22:28:30.620408 cellar[1461:360470] dismiss
2017-11-28 22:28:31.537588 cellar[1461:360413] username not present
2017-11-28 22:28:32.126759 cellar[1461:360413] [App] if we're in the 
real pre-commit handler we can't actually add any new fences due to CA 
restriction

非常感谢您的帮助。谢谢

不确定这是否是您遇到问题的原因,但看起来您不是 运行 主线程上的 dismiss() 调用。您应该在主线程上调用所有 UI 代码。包装如下

     case .Success(let result):
        //print(result)
        DispatchQueue.main.async { 
            self.dismissSelf()
        }
     break