通过 self 更新闭包内的 UI 是一种不好的做法吗?

Posted

技术标签:

【中文标题】通过 self 更新闭包内的 UI 是一种不好的做法吗?【英文标题】:Updating UI inside a closure via self a bad practice? 【发布时间】:2016-11-21 02:31:04 【问题描述】:

我对多线程编程还很陌生,到目前为止,我一直在通过 self.myview.setTitle, etc. 更新闭包内的 UI/视图

这是我如何在处理程序/闭包中更新 UI 的示例代码

SFSpeechRecognizer.requestAuthorization  (authStatus) in
        switch authStatus
        
        case .authorized:
            self.recordButton.isEnabled = true
        case .denied:
            self.recordButton.isEnabled = false
            self.recordButton.setTitle("User denied access to speech recognition", for: .disabled)
        case .restricted:
            self.recordButton.isEnabled = false
            self.recordButton.setTitle("Speech recognition is disabled for this device", for: .disabled)
        case .notDetermined:
            self.recordButton.isEnabled = false
            self.recordButton.setTitle("Speech recognition has not yet been authorized", for: .disabled)
        default:
            break;
        
    

这只是我一直在做的一个示例,但我也为其他任务执行此操作,例如从天气 API 下载 json 数据并相应地更新我的 UI 等。

现在我听说这是不好的做法,我希望知道原因。另外,在闭包线程中更新 UI 的正确方法是什么?

【问题讨论】:

【参考方案1】:

在闭包内更新 UI 一点也不坏。

但是完全错误并且明确禁止在除主线程之外的任何线程上更新 UI。而且您不知道您的闭包是否在主线程上被调用(并运行)。一般而言,在主线程上调用一个名为异步的完成处理程序是不确定或不可能的。

因此,您应该证明这段代码在主线程上运行,或者通过故意进入主线程来确定更新 UI 之前的线程。

【讨论】:

欣赏信息。我无法证明代码在主线程上运行,因为我不知道。那么,通常不是使用self.someview.,而是调用 DispatchQueue 来获取主线程并在那里更新 UI,这通常是一个好主意吗? 为了安全起见,是的。这正是我的回答要告诉你的。 换一种说法:您似乎误解了在这种情况下潜在的“不良做法”是什么。我的回答试图为您解决这个问题。这不是句法的事情,而是线程的事情。 感谢您澄清这一点。顺便说一句,这仅适用于 UI 对吗?我的意思是,我可以像在后台线程中一样更新任何其他非视图变量?例如,我有一个实例变量数组,我正在从网上获取一些东西。然后我可以将结果存储在数组中,而无需获取主线程并在那里执行,对吗?为新手问题道歉,但我还是多线程编程实践的新手。 没有关于在哪个线程上更新实例属性的规定,但危险确实潜伏在这里。主线程总是安全的,因为只有一个而且它是串行的。如果您使用另一个线程,您需要知道自己在做什么,否则事情可能会以非常神秘的方式出错。

以上是关于通过 self 更新闭包内的 UI 是一种不好的做法吗?的主要内容,如果未能解决你的问题,请参考以下文章

另一个闭包内的闭包

将目标添加到闭包内的按钮不起作用

前端面试题的做错的题(刷题才更新)

异步调用的空闭包

为什么这个knockoutjs observableArray不会导致UI更新?

JavaScript:闭包是不是可以通过值而不是像 PHP 中的引用来访问封闭范围内的变量?