[英]Why is [weak self] or [unowned self] not needed in Operation Queue?
After learning about Swift's capture list and how it can be used to avoid retain cycle, I can't help noticing something puzzling about OperationQueue
: it doesn't need either [weak self]
or [unowned self]
to prevent memory leak. 在了解了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.
}
}
I don't see why adding an operation would not cause a retain cycle: SomeManager
strongly owns the queue
, which in turns strongly owns the added closures. 我不明白为什么添加操作不会导致保留周期:
SomeManager
强烈拥有queue
,而后者又强烈拥有添加的闭包。 Each added closure strongly refers back to SomeManager
. 每个添加的闭包都强烈地指向
SomeManager
。 This should theoretically create a retain cycle leading to memory leak. 从理论上讲,这应该创建一个导致内存泄漏的保留周期。 Yet Instruments shows that everything is perfectly fine.
然而,乐器显示一切都很好。
Why is this the case? 为什么会这样呢? In some other multi-threaded, block-based APIs, like
DispatchSource
, you seem to need the capture list. 在其他一些基于块的多线程API中,例如
DispatchSource
,您似乎需要捕获列表。 See Apple's sample code ShapeEdit
for example, in ThumbnailCache.swift
: 例如,在
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()
}
But in the same code file, OperationQueue
doesn't need the capture list, despite having the same semantics: you hand over a closure with reference to self
to be executed asynchronously: 但是,在相同的代码文件中,
OperationQueue
尽管具有相同的语义,但不需要捕获列表:您将引用self
的闭包交给异步执行:
fileprivate let workerQueue: OperationQueue { ... }
...
self.workerQueue.addOperation {
if let thumbnail = self.loadThumbnailFromDiskForURL(URL) {
...
self.cache.setObject(scaledThumbnail!, forKey: documentIdentifier as AnyObject)
}
}
I have read about Swift's capture list above, as well as related SO answers like this and this and this , but I still don't know why [weak self]
or [unowned self]
are not needed in OperationQueue
API while they are in Dispatch
API. 我已经阅读了上面有关Swift的捕获列表 ,以及相关的SO答案,例如this和this和this ,但是我仍然不知道为什么在
Dispatch
, OperationQueue
API中不需要[weak self]
或[unowned self]
API。 I'm also not sure how no leaks are found in OperationQueue
case. 我也不确定在
OperationQueue
案例中如何找不到泄漏。
Any clarifications would be much appreciated. 任何澄清将不胜感激。
In addition to the accepted answer below, I also find the comment by QuinceyMorris in Apple forums quite helpful. 除了下面可接受的答案外,我还发现QuinceyMorris在Apple论坛中的评论非常有帮助。
You do have a retain cycle there, but that doesn't automatically lead to a memory leak. 您确实有一个保留周期,但这不会自动导致内存泄漏。 After the queue finished the operation it releases it thus breaking the cycle.
队列完成操作后,它将释放它,从而中断了循环。
Such an temporary retain cycle can be very useful in some situations as you won't have to hang on to an object and still have it finish its work. 在某些情况下,这样的临时保留周期非常有用,因为您不必挂在某个对象上,而仍然可以完成它的工作。
As an experiment you can suspend the queue. 作为实验,您可以暂停队列。 Then you will see the memory leak.
然后,您将看到内存泄漏。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.