Swift-正在检查弱变量是否为零线程安全?

Swift-正在检查弱变量是否为零线程安全?,swift,queue,thread-safety,weak-references,abort,Swift,Queue,Thread Safety,Weak References,Abort,我有一个长时间运行的进程,我希望能够中断它 func longProcess (shouldAbort: @escaping ()->Bool) { // Runs a long loop and periodically checks shouldAbort(), // returning early if shouldAbort() returns true } 下面是我使用它的班级: class Example { private var abortF

我有一个长时间运行的进程,我希望能够中断它

func longProcess (shouldAbort: @escaping ()->Bool) {

    // Runs a long loop and periodically checks shouldAbort(),
    // returning early if shouldAbort() returns true

}
下面是我使用它的班级:

class Example {

    private var abortFlag: NSObject? = .init()

    private var dispatchQueue: DispatchQueue = .init(label: "Example")

    func startProcess () {
        let shouldAbort: ()->Bool = { [weak abortFlag] in
            return abortFlag == nil
        }

        dispatchQueue.async {
            longProcess(shouldAbort: shouldAbort)
        }
    }

    func abortProcess () {
        self.abortFlag = nil
    }
}

shoulldabort
闭包捕获对
abortFlag
weak
引用,并检查该引用是否指向
nil
NSObject
。由于引用是
弱的
,如果原始的
NSObject
被解除分配,那么闭包捕获的引用将突然变成
nil
,闭包将开始返回
true
。关闭将在
longProcess
函数期间重复调用,该函数发生在私有
dispatchQueue
上。
Example
类上的
abortProcess
方法将从其他队列外部调用。如果有人调用
abortProcess()
,从而解除分配
abortFlag
,而
longProcess
正试图执行检查以查看
abortFlag
是否已解除分配,该怎么办?检查
myWeakReference==nil
是否为线程安全操作?

您可以将已调度的任务创建为
DispatchWorkItem
,它已经具有线程安全属性。然后,您可以将该
DispatchWorkItem
分派到队列,并让它定期检查其
isCancelled
。然后,您就可以在您想要停止它的时候将其调度为该点


或者,在尝试将某些工作包装到对象中时,我们通常使用
操作
,它将任务很好地封装在自己的类中:

class SomeLongOperation: Operation {
    override func main() {
        // Runs a long loop and periodically checks `isCancelled`

        while !isCancelled {
            Thread.sleep(forTimeInterval: 0.1)
            print("tick")
        }
    }
}
要创建队列并将操作添加到该队列,请执行以下操作:

let queue = OperationQueue()
let operation = SomeLongOperation()
queue.addOperation(operation)
以及取消该项操作:

operation.cancel()


总之,无论您使用
操作
(坦率地说,这是将某个任务包装到自己的对象中的“转到”解决方案),还是使用
DispatchWorkItem
滚动自己的解决方案,想法都是一样的,即您不需要拥有自己的状态属性来检测任务的取消。调度队列和操作队列都有很好的机制来简化这个过程。

我看到这个bug()表明弱引用读取不是线程安全的,但它已经被修复,这表明(运行时没有任何bug),弱引用读取是线程安全的


同样有趣的是:

首先为什么要使用这个虚拟的
NSObject
实例?看来这玩意儿也一样管用。忽略我的答案。事实上这是正确的(也很有趣),但罗布的建议更好。我同意Rob的建议是可行的,这就是为什么我投了更高的票,但我的问题只是部分出于需要,另一部分是好奇心。你直接回答了我的问题,所以你的答案是正确的。我很高兴读过Rob的答案,也很高兴这篇文章的一部分是供其他人阅读的
queue.cancelAllOperations()