简体   繁体   English

为什么在“操作队列”中不需要[弱我]或[无主我]?

[英]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答案,例如thisthisthis ,但是我仍然不知道为什么在DispatchOperationQueue 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. 任何澄清将不胜感激。

Edit 编辑

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.

相关问题 为什么[弱自我]工作但是[无主自我]在Swift闭包中中断? - Why does [weak self] work but [unowned self] break in a Swift closure? 在异步网络请求中捕获自身弱或无主 - Capturing self weak or unowned on asynchronous network requests 封闭说明中的强,弱和无主自我 - Strong, weak and unowned self in closures explanation 当我们不应该既不使用[弱自我]也不使用[无主自我]? - When we should NOT use neither [weak self] nor [unowned self]? 在此关闭过程中,我需要[无主的自我]还是[弱的自我]? - Do I need [unowned self] or [weak self] in this closure? 我需要[弱自我]或[无主自我]来解决封闭中的Singleton吗? - Do I need [weak self] or [unowned self] for a Singleton in the Closure? 为什么在呼叫[无名的自我]时将自我释放 - Why self is deallocated when calling [unowned self] 内部闭包的捕获列表是否需要将“self”重新声明为“weak”或“unowned”? - Do capture lists of inner closures need to redeclare `self` as `weak` or `unowned`? MVVM:使用闭包,无主或弱自我将View与ViewModel绑定? - MVVM: binding the View with the ViewModel with closures, unowned or weak self? 自我解雇期间,弱者,强者或无主者都不会做吗? - Neither weak nor strong or unowned will do during self dismissal?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM