gpt4 book ai didi

ios - 如何确保我的 DispatchQueue 专门在主线程上执行一些代码?

转载 作者:行者123 更新时间:2023-11-28 23:21:32 25 4
gpt4 key购买 nike

我有一个管理数组的单例。这个单例可以从多个线程访问,所以它有自己的内部 DispatchQueue 来管理跨线程的读/写访问。为简单起见,我们将其称为串行队列。

有时单例将从数组中读取数据并更新 UI。我该如何处理?

不知道我的内部调度队列是哪个线程,对吧?这只是一个我不用担心的实现细节?在大多数情况下,这似乎没问题,但在这个特定函数中,我需要确保它使用主线程。

是否可以按照以下方式做某事:

myDispatchQueue.sync { // Synchronize with internal queue to ensure no writes/reads happen at the same time
DispatchQueue.main.async { // Ensure that it's executed on the main thread
for item in internalArray {
// Pretend internalArray is an array of strings
someLabel.text = item
}
}
}

所以我的问题是:

  1. 可以吗?嵌套调度队列似乎很奇怪/错误。有没有更好的办法?也许像 myDispatchQueue.sync(forceMainThread: true) { ... }
  2. 如果我没有使用 DispatchQueue.main.async { ... },并且我从主线程调用该函数,我能否确定我的内部调度队列将在与所谓的相同(主)线程?或者这也是一个“实现细节”,但它也可以在后台线程上调用?

基本上我感到困惑的是,线程似乎是您不应该为队列担心的实现细节,但是当您确实需要担心时,偶尔会发生什么?

简单示例代码:

class LabelUpdater {
static let shared = LabelUpdater()

var strings: [String] = []
private let dispatchQueue: dispatchQueue

private init {
dispatchQueue = DispatchQueue(label: "com.sample.me.LabelUpdaterQueue")
super.init()
}

func add(string: String) {
dispatchQueue.sync {
strings.append(string)
}
}

// Assume for sake of example that `labels` is always same array length as `strings`
func updateLabels(_ labels: [UILabel]) {
// Execute in the queue so that no read/write can occur at the same time.
dispatchQueue.sync {
// How do I know this will be on the main thread? Can I ensure it?
for (index, label) in labels.enumerated() {
label.text = strings[index]
}
}
}
}

最佳答案

是的,您可以将对一个队列的调度嵌套在对另一个队列的调度中。我们经常这样做。

但是要非常小心。仅使用来自同步队列的分派(dispatch)将异步分派(dispatch)包装到主队列是不够的。您的第一个示例不是线程安全的。您从主线程访问的数组可能会从您的同步队列中发生变化:

enter image description here

这是一个 race condition因为您可能有多个线程(您的同步队列的线程和主线程)与同一个集合交互。与其将分派(dispatch)到主队列的 block 直接与 objects 交互,不如复制它的副本,这就是在分派(dispatch)到主队列中引用的内容。

例如,您可能想要执行以下操作:

func process(completion: @escaping (String) -> Void) {
syncQueue.sync {
let result = ... // note, this runs on thread associated with `syncQueue` ...

DispatchQueue.main.async {
completion(result) // ... but this runs on the main thread
}
}
}

这确保主队列不与此类的任何内部属性交互,而只是将在此闭包中创建的 result 传递给 syncQueue


请注意,所有这些都与它是一个单例无关。但是既然你提出了这个话题,我建议不要对模型数据使用单例。它适用于接收器、无状态 Controller 等,但通常不建议用于模型数据。

我绝对不鼓励直接从单例启动 UI 控件更新的做法。我倾向于提供这些方法完成处理程序闭包,并让调用者负责生成的 UI 更新。当然,如果您想将闭包分派(dispatch)到主队列(为方便起见,在许多第三方 API 中很常见),那很好。但是单例不应该进入并更新 UI 控件本身。

我假设您所做的所有这些只是为了说明目的,但我向可能不会理解这些担忧的 future 读者添加了这个警告词。

关于ios - 如何确保我的 DispatchQueue 专门在主线程上执行一些代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59615860/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com