代码之家  ›  专栏  ›  技术社区  ›  Manuel

如何在gcd中防止释放对象?

  •  0
  • Manuel  · 技术社区  · 7 年前

    此函数用于重新安排工作项的执行:

    class MyClass {
    
        var id: String?
        var workItem: DispatchWorkItem?
        var isDoing = false
    
        func myFunction() {
    
            guard let id = self.id else { return }
    
            isDoing = true
            NotificationCenter.default.post(name: MyNotification, object: nil, userInfo: ["id": id])
            workItem?.cancel()
    
            workItem = DispatchWorkItem {
                self.isDoing = false
                NotificationCenter.default.post(name: MyNotification, object: nil, userInfo: ["id": id])
            }
    
            if let workItem = workItem { 
                DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + DispatchTimeInterval.seconds(10), execute: workItem)
            }
        }
    }
    

    它在开发中运行良好,但设计似乎可疑,所以我问一些基本问题:

    1. workItem 如果没有 workItem?.cancel() 在队列尝试执行 工作项 是吗?
    2. id 里面 工作项 什么时候都没有 工作项 由作用域执行或保留 let id = self.id 是吗?
    3. isDoing 里面 工作项 工作项 如果 MyClass 对象已被释放?换句话说,预定的 工作项 类名 对象已解除分配?
    1 回复  |  直到 7 年前
        1
  •  1
  •   mag_zbc    7 年前
    1. 不知道你是什么意思。你不能全力以赴 workItem 任何地方。

    2. 不,不可能 nil 因为你在处理一个局部变量 self.id 是的。通过使用 guard 确保本地变量 id 不是nil,闭包保留对捕获值的强引用(默认情况下),因此不会释放它。

    3. isDoing 是的实例变量 MyClass 所以之前不能解除 类名 实例已释放。问题是,对你来说 类名 无法解除分配,因为您正在查看一个强引用周期。默认情况下,闭包保持对所捕获值的强引用,并且正在捕获。 self 是的。从那以后 自己 强烈地引用 工作项 ,从而保留了对捕获 自己 ,因此是参考周期。

    一般来说,当捕获 自己 使用捕获列表处理对 自己 并检查它是否还没有被释放

    workItem = DispatchWorkItem { [weak self] in
        guard let strongSelf = self else { return }
        // do stuff with strongSelf
    }
    
    推荐文章