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

时间:2018-06-25 12:52:41

标签: ios swift grand-central-dispatch dispatchworkitem

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

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()workItem可以为空吗?
  2. 在执行id时,workItem中的workItem可以为空吗?还是由范围let id = self.id保留了?
  3. 如果isDoing对象已经被释放,那么workItem内部的workItem是否已经被释放?换句话说,当释放MyClass对象时,调度的workItem会发生什么?

1 个答案:

答案 0 :(得分:1)

  1. 不确定您的意思。您不会在任何地方淘汰workItem

  2. 否,因为您正在使用局部变量-nil的副本,所以不能为self.id。通过使用guard,您可以确保局部变量id不为nil,并且闭包为捕获的值保留了一个强引用(默认情况下),因此不会将其释放。

  3. isDoingMyClass的实例变量,因此在释放MyClass实例之前不能释放它。问题是,在您的情况下,MyClass无法释放,因为您正在寻找一个强大的参考周期。默认情况下,闭包对捕获的值保持强烈引用,您正在捕获self。而且,由于self强烈引用workItem,因此又强烈引用了捕获self的闭包,因此引用周期也很大。

通常,在捕获self时,您会使用捕获列表来处理对self的弱引用,并检查是否未释放

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