![](/img/trans.png)
[英]Why does [weak self] work but [unowned self] break in a Swift closure?
[英]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答案,例如this和this和this ,但是我仍然不知道為什么在Dispatch
, OperationQueue
API中不需要[weak self]
或[unowned self]
API。 我也不確定在OperationQueue
案例中如何找不到泄漏。
任何澄清將不勝感激。
除了下面可接受的答案外,我還發現QuinceyMorris在Apple論壇中的評論非常有幫助。
您確實有一個保留周期,但這不會自動導致內存泄漏。 隊列完成操作后,它將釋放它,從而中斷了循環。
在某些情況下,這樣的臨時保留周期非常有用,因為您不必掛在某個對象上,而仍然可以完成它的工作。
作為實驗,您可以暫停隊列。 然后,您將看到內存泄漏。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.