0

此功能应该重新安排工作项的执行:

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是 nil,如果 workItem?.cancel()在队列尝试执行workItem?
  2. id执行时inside可能workItem是 nilworkItem还是由 scoped 保留let id = self.id
  3. 如果对象已被释放,isDoing内部workItem是否已经被释放?换句话说,当对象被释放时,调度会发生什么?workItemMyClassworkItemMyClass
4

1 回答 1

2
  1. 不明白你的意思。你在任何地方都不会出局workItem

  2. 不,这不可能,nil因为您正在使用局部变量 - self.id. 通过使用guard,您可以确保局部变量id不为零,并且闭包保持对捕获值的强引用(默认情况下),因此它不会被释放。

  3. isDoing是一个实例变量,MyClass所以它不能在MyClass实例被释放之前被释放。问题是,在您的情况下MyClass无法解除分配,因为您正在查看一个强大的参考周期。默认情况下,闭包保持对捕获的值的强引用,并且您正在捕获self. 并且因为self保持对 的强引用workItem,这反过来又保持对捕获的闭包的强引用self,因此引用循环。

通常,在捕获时,self您使用捕获列表来处理弱引用self并检查它是否没有被释放

workItem = DispatchWorkItem { [weak self] in
    guard let strongSelf = self else { return }
    // do stuff with strongSelf
}
于 2018-06-25T14:53:17.357 回答