我强烈建议您使用DispatchQueue(s)
由...提供大中央快讯,它们使多线程管理变得更加容易。
Command
让我们从您的命令类开始
class Command {
let id: String
var isAck = false
var isSent = false
init(id:String) {
self.id = id
}
}
Queue
现在我们可以构建我们的Queue
类,它将提供以下功能
这是我们的类不应该与DispatchQueue的概念混淆!
- push a
Command
进入队列
- 删除一个
Command
从队列中
- 开始加工队列中的所有元素
现在是代码:
class Queue {
typealias Element = (date:Date, command:Command)
private var storage: [Element] = []
private let serialQueue = DispatchQueue(label: "serialQueue")
func push(command:Command) {
serialQueue.async {
let newElement = (Date(), command)
self.storage.append(newElement)
}
}
func delete(by id: String) {
serialQueue.async {
guard let index = self.storage.index(where: { $0.command.id == id }) else { return }
self.storage.remove(at: index)
}
}
func startProcessing() {
Timer.scheduledTimer(withTimeInterval: 10, repeats: true) { timer in
self.processElements()
}
}
private func processElements() {
serialQueue.async {
// send messages where isSent == false
let shouldBeSent = self.storage.filter { !$0.command.isSent }
for elm in shouldBeSent {
// TODO: add here code to send message
elm.command.isSent = true
}
// remove from storage message where isAck == true
self.storage = self.storage.filter { !$0.command.isAck }
}
}
}
它是如何工作的?
正如你所看到的storage
property 是一个包含元组列表的数组,每个元组有 2 个组件:Date
and Command
.
自从storage
数组是由多个线程访问的,我们需要确保以线程安全的方式访问它。
所以每次我们访问storage
我们将代码包装到这里
serialQueue.async {
// access self.storage safely
}
我们在上面所示的闭包中写入的每个代码都会添加到我们的串行调度队列.
串行队列当时确实处理了 1 个闭包。这就是为什么我们的存储属性以线程安全的方式访问!
最终考虑
下面的代码块是邪恶的
while true {
...
}
它确实使用了所有可用的 CPU 时间,它确实冻结了 UI(在主线程上执行时)并释放电池电量。
正如你所看到的,我将其替换为
Timer.scheduledTimer(withTimeInterval: 10, repeats: true) { timer in
self.processElements()
}
哪个调用self.processElements()
每 10 秒一次,为 CPU 留下足够的时间来处理其他线程。
当然,您可以更改秒数以更好地适应您的场景。