完成 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
我有一个我无法解决的行为。 我有一个控制器(控制器 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