Swift - 检查弱变量是不是为 nil 或不是线程安全的?

Posted

技术标签:

【中文标题】Swift - 检查弱变量是不是为 nil 或不是线程安全的?【英文标题】:Swift - Is checking whether a weak variable is nil or not thread-safe?Swift - 检查弱变量是否为 nil 或不是线程安全的? 【发布时间】:2019-07-18 15:47:24 【问题描述】:

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

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
    

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

【问题讨论】:

你为什么首先使用这个虚拟的NSObject 实例?看起来布尔值也一样。 忽略我的回答。这实际上是正确的(也很有趣),但 Rob 的建议更好。只是不要这样做。 我同意 Rob 的建议是可行的方法,这就是我支持它的原因,但我的问题只是部分出于需求,另一部分是好奇心。你直接回答了我的问题,所以你的答案是正确的。我很高兴阅读了 Rob 的答案,并且它作为这篇文章的一部分存在供其他人阅读 【参考方案1】:

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


或者,当尝试将一些工作包装在一个对象中时,我们经常使用Operation,它可以很好地将任务封装在自己的类中:

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()

或者

queue.cancelAllOperations()

底线,无论您使用Operation(坦率地说,这是将某些任务包装在其自己的对象中的“首选”解决方案)还是使用DispatchWorkItem自行滚动,想法都是一样的,即您不需要拥有自己的 state 属性来检测任务的取消。调度队列和操作队列都已经有了很好的机制来为你简化这个过程。

【讨论】:

【参考方案2】:

我看到这个错误 (Weak properties are not thread safe when reading SR-192) 表明弱引用读取不是线程安全的,但它已被修复,这表明(在运行时没有任何错误),弱引用读取旨在是线程安全的.

也很有趣:Friday Q&A 2017-09-22: Swift 4 Weak References by Mike Ash

【讨论】:

以上是关于Swift - 检查弱变量是不是为 nil 或不是线程安全的?的主要内容,如果未能解决你的问题,请参考以下文章

Swift:尝试测试 ObservedObject 变量是不是为 nil 时的 EXC_BREAKPOINT

下划线符号是不是会忽略或检查 Swift 中 switch 语句中的无效性?

Swift:当变量不是可选时,处理意外的 nil 值

检查 NSFont 在 Swift 中是不是为粗体

如果变量不是 nil,如何在 swift UI 中显示文本视图?

可选关闭并检查它是不是为 nil