swift - 为什么Operation Queue中不需要[weak self]或[unowned self]?

标签 swift memory-leaks automatic-ref-counting nsoperationqueue retain-cycle

了解后Swift's capture list以及如何使用它来避免保留循环,我不禁注意到关于 OperationQueue 的一些令人费解的事情:它不需要 [weak self] [unowned self] 防止内存泄漏。

class SomeManager {
    let queue = OperationQueue()
    let cache: NSCache = { () -> NSCache<AnyObject, AnyObject> in
        let cache = NSCache<AnyObject, AnyObject>()
        cache.name = "huaTham.TestOperationQueueRetainCycle.someManager.cache"
        cache.countLimit = 16
        return cache
    }()

    func addTask(a: Int) {
        queue.addOperation { // "[unowned self] in" not needed?
            self.cache.setObject(a as AnyObject, forKey: a as AnyObject)
            print("hello \(a)")
        }
    }
}

class ViewController: UIViewController {

    var someM: SomeManager? = SomeManager()

    override func viewDidLoad() {
        super.viewDidLoad()
        someM?.addTask(a: 1)
        someM?.addTask(a: 2)
    }

    // This connects to a button.
    @IBAction func invalidate() {
        someM = nil  // Perfectly fine here. No leak.
    }
}

我不明白为什么添加操作不会导致保留周期:SomeManager 强烈拥有 queue,后者又强烈拥有添加的闭包。每个添加的闭包都强烈引用回 SomeManager。这在理论上应该会创建一个导致内存泄漏的保留循环。然而 Instruments 显示一切都很好。

No Leak

为什么会这样?在其他一些多线程、基于 block 的 API 中,例如 DispatchSource,您似乎需要捕获列表。参见 Apple's sample code ShapeEdit 例如,在 ThumbnailCache.swift 中:

fileprivate var flushSource: DispatchSource
...
flushSource.setEventHandler { [weak self] in   // Here
    guard let strongSelf = self else { return }

    strongSelf.delegate?.thumbnailCache(strongSelf, didLoadThumbnailsForURLs: strongSelf.URLsNeedingReload)
    strongSelf.URLsNeedingReload.removeAll()
}

但在同一个代码文件中,OperationQueue 不需要捕获列表,尽管具有相同的语义:您将引用 self 的闭包传递给异步执行:

fileprivate let workerQueue: OperationQueue { ... }
...
self.workerQueue.addOperation {
    if let thumbnail = self.loadThumbnailFromDiskForURL(URL) {
        ...
        self.cache.setObject(scaledThumbnail!, forKey: documentIdentifier as AnyObject)
    }
}

我读过 Swift's capture list以上,以及相关的 SO 答案,如 thisthisthis ,但我仍然不知道为什么 [weak self][unowned self]OperationQueue API 中不需要,而它们在 调度 API。我也不确定在 OperationQueue 案例中如何没有发现泄漏。

如有任何说明,我们将不胜感激。

编辑

除了下面接受的答案外,我还找到了 the comment by QuinceyMorris in Apple forums很有帮助。

最佳答案

那里确实有一个保留循环,但这不会自动导致内存泄漏。队列完成操作后,它会释放它,从而打破循环。

这种临时保留周期在某些情况下非常有用,因为您不必卡在一个对象上并仍然让它完成它的工作。

作为实验,您可以暂停队列。然后你会看到内存泄漏。

关于swift - 为什么Operation Queue中不需要[weak self]或[unowned self]?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48124071/

相关文章:

c++ - 一种编码风格能绝对保证没有内存泄漏吗?

ios - 为什么 NSNotification block 中的这个 NSArray(显然)永远不会在 ARC 环境中发布?

objective-c - 为什么ARC转换将 "weak"装饰器添加到 "readonly"属性?

ios - 在 UINavigationBar 上设置导航项时崩溃

ios - 在 Realm 中保存许多图像(每个图像小于 2MB)是个好主意吗?

ios - 找不到类型 "UITableViewRowAction"的初始值设定项

xcode - NSPopupButton 的值为零

ios - 无法弄清楚如何解决内存泄漏

objective-c - 为什么在使用 [NSDate date] 时 ARC 不释放内存但使用 [[NSDate alloc] init] 却工作正常?

javascript - 使用 socket.io 的内存泄漏