iOS更改UI时应从主线程调用什么?

时间:2019-01-18 12:51:28

标签: ios swift multithreading thread-safety

我有一个用于警报提示的扩展程序。当showAlert()不是从主线程调用时,我得到“不是从主线程更改UI”的行为。有时根本没有发出警报,有时延迟很大。没有崩溃。但是,如果我将所有函数的代码放在DispatchQueue.main.async闭包中-一切都很好。为什么?我不应该只从主线程中调用实际上更改UI的代码吗?

@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 个答案:

答案 0 :(得分:3)

简短的回答:UIKit不是线程安全的。您应该从主线程对UIKit进行 ALL 调用,包括在UIKit对象上创建或设置属性。很少有 例外,但只有少数例外,并且通常都有据可查。与主线程中的UIKit对象进行交互永远不会出错,而与后台线程中的UIKit对象进行交互几乎总是不好。 (其结果是“不确定的”,有时甚至是致命的。)

如果您与主线程中的UIKit对象进行 ALL 交互,则不会有任何并发​​问题。在后台执行耗时的联网和/或数字运算代码,然后包装该代码以在调用主线程时将结果呈现给用户。

答案 1 :(得分:2)

您是正确的,所有UI更改操作都应仅在主线程上完成。 如果不是这样,即使您要用您的代码更新UI,系统也不会保证您何时,以什么顺序进行。

现在,您想让主线程尽可能地混乱,而只放置与UI相关的代码是正确的。但是,如果您仔细看一下这些行,您会注意到这些:

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

也在修改UI,但是在主闭包之外。 我相信,如果您在主线程上移动这两行,您的警告将消失!

答案 2 :(得分:0)

可能是您从后台调用show alert方法 因此,您正在使用此代码调用主线程

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

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