代码之家  ›  专栏  ›  技术社区  ›  BadCodeDeveloper

iOS在更改用户界面时,我应该从主线程调用什么?

  •  0
  • BadCodeDeveloper  · 技术社区  · 6 年前

    我有一个提醒演示的扩展。什么时候? showAlert() 不是从主线程调用的,我得到了“更改用户界面而不是从主线程”的行为。有时警报根本就没有出现,有时有很大的延迟。没有撞车事故。但是如果我把函数的所有代码都放在 DispatchQueue.main.async 关闭-一切正常。为什么?我不应该只从主线程调用实际更改用户界面的代码吗?

    @objc extension UIAlertController {
    
    static func showAlert(title: String?, message: String? = nil, closeActionTitle: String? = "OK", preferredStyle: UIAlertControllerStyle = .alert, actions: [UIAlertAction]? = nil) {
            let alertController = UIAlertController(title: title,
                                                    message: message,
                                                    preferredStyle: preferredStyle)
            var allActions = [UIAlertAction]()
            if let closeTitle = closeActionTitle {
                allActions.append(UIAlertAction(title: closeTitle, style: .cancel))
            }
            allActions.append(contentsOf: actions ?? [])
            allActions.forEach { alertController.addAction($0) }
    
            let vc = ClearViewController()
            let window = UIWindow(frame: UIScreen.main.bounds)
            window.rootViewController = vc
            window.backgroundColor = AppTheme.color.clear
            window.windowLevel = UIWindowLevelAlert
    
        DispatchQueue.main.async {
            window.makeKeyAndVisible()
            vc.present(alertController, animated: true)
        }
    }
    

    }

    3 回复  |  直到 6 年前
        1
  •  2
  •   Thomas    6 年前

    您是正确的,所有UI更改操作都应该只在主线程上完成。 如果没有,则系统不会向您保证何时使用您的代码更新UI,按哪个顺序进行更新。

    现在,您想要尽可能少地混乱主线程,只放置与UI相关的代码是正确的。但是如果你仔细观察这些线条,你会发现:

    let window = UIWindow(frame: UIScreen.main.bounds)
    window.rootViewController = vc
    

    它们也在修改用户界面,但在主闭包之外。 我相信如果你在主线上移动这两条线,你的警告就会消失!

        2
  •  3
  •   Duncan C    6 年前

    简短回答: UIKit 不是线程安全的。你应该做 所有 呼吁 乌伊特 ,包括在上创建或设置属性 乌伊特 对象,来自主线程。有一个 很少的 这方面的小例外,但只有少数例外,而且它们通常都有很好的文档记录。与…互动 乌伊特 来自主线程的对象从不坏,并且与 乌伊特 来自后台线程的对象几乎总是不好的。(结果“未定义”,有时是致命的。)

    如果你这样做了 所有 与…互动 乌伊特 来自主线程的对象不会有任何并发问题。在后台处理耗时的网络和/或数字处理代码,然后包装代码以在调用主线程时向用户显示结果。

        3
  •  0
  •   Jogendar Choudhary    6 年前

    可能您正在从后台调用Show Alert方法 所以您用这个代码调用主线程

    DispatchQueue.main.async {
        window.makeKeyAndVisible()
        vc.present(alertController, animated: true)
    }
    

    所有UI更改都应在主线程中。