簡體   English   中英

為什么在“操作隊列”中不需要[弱我]或[無主我]?

[英]Why is [weak self] or [unowned self] not needed in Operation Queue?

在了解了Swift的捕獲列表以及如何使用它來避免保留周期之后,我不禁注意到有關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 從理論上講,這應該創建一個導致內存泄漏的保留周期。 然而,樂器顯示一切都很好。

無泄漏

為什么會這樣呢? 在其他一些基於塊的多線程API中,例如DispatchSource ,您似乎需要捕獲列表。 例如,在ThumbnailCache.swift ,請參閱Apple的示例代碼 ShapeEdit

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的捕獲列表 ,以及相關的SO答案,例如thisthisthis ,但是我仍然不知道為什么在DispatchOperationQueue API中不需要[weak self][unowned self] API。 我也不確定在OperationQueue案例中如何找不到泄漏。

任何澄清將不勝感激。

編輯

除了下面可接受的答案外,我還發現QuinceyMorris在Apple論壇中的評論非常有幫助。

您確實有一個保留周期,但這不會自動導致內存泄漏。 隊列完成操作后,它將釋放它,從而中斷了循環。

在某些情況下,這樣的臨時保留周期非常有用,因為您不必掛在某個對象上,而仍然可以完成它的工作。

作為實驗,您可以暫停隊列。 然后,您將看到內存泄漏。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM