【问题标题】:Avoiding strong reference when passing a method to a function将方法传递给函数时避免强引用
【发布时间】:2016-11-04 18:24:27
【问题描述】:

将方法传递给采用闭包的函数时,我可以使用 someFunc(closure: someMethod) orsomeFunc() { [unowned self] in self.someMethod() }`。

第一个较短,但具有很强的参考意义。如何在避免这种强引用的同时使用它?

这是一个演示,其中包含泄漏的一个和好的一个: https://swiftlang.ng.bluemix.net/#/repl/581ccd3a0bdc661a6c566347

import Foundation

private var instanceCounter = 0

class Leak : NSObject {

    override init() {
        super.init()
        instanceCounter += 1
    }

    deinit {
        instanceCounter -= 1
    }
}

class OnFunctionLeak : Leak {

    override init() {
        super.init()
        _ = NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "OnFunctionLeak"),
                                               object: nil,
                                               queue: nil,
                                               usingBlock: doNothing)
    }

    func doNothing(_ notif: Notification) { }

    deinit {
        NotificationCenter.default.removeObserver(self)
    }
}

class OnClosureLeak : Leak {

    override init() {
        super.init()
        _ = NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "OnFunctionLeak"),
                                               object: nil,
                                               queue: nil) { [unowned self] notif in
            self.doNothing(notif)
        }
    }

    func doNothing(_ notif: Notification) { }

    deinit {
        NotificationCenter.default.removeObserver(self)
    }
}

var onFunctionLeak: OnFunctionLeak? = OnFunctionLeak()
onFunctionLeak = nil

//XCTAssertEqual(instanceCounter, 0)
print("instanceCounter: \(instanceCounter) == 0")

instanceCounter = 0
var onClosureLeak: OnClosureLeak? = OnClosureLeak()
onClosureLeak = nil

//XCTAssertEqual(instanceCounter, 0)
print("instanceCounter: \(instanceCounter) == 0")

较短的选择在第 26 行,如果我将 doNothing 替换为 { [unowned self] notif in self.doNothing(notif) },那么强引用就消失了。

有什么想法吗?

【问题讨论】:

  • 相关:How to remove strong reference cycle from closure from method? 我认为没有更好的方法可以避免在不使用闭包的情况下对self 进行强引用,例如在您的第二个示例中。
  • 我读过它并要求确定。但是如果被证实了,我的想法是如果它总是会创建一个隐藏的强引用,那么为什么允许直接写这个问题,那么容易出错。
  • 顺便说一句,调用“NotificationCenter.default.removeObserver(self)”通常被认为是不好的做法——这可能会弄乱父类,因此 Apple 鼓励您一一删除您的观察结果。

标签: swift function closures strong-references


【解决方案1】:

如何在避免这种强引用的同时使用它?

你不能。

只有内联定义的匿名函数(在使用时)可以有一个捕获列表(例如[unowned self])。因此,只有匿名函数才能提供您所要求的功能。用func 定义的函数根本做不到。

这只是关于 Swift 的事实。

(这可能有潜在的原因;我怀疑原因与存储有关。func 函数以某种方式静态存储。但内联定义的匿名函数不是;它的出现时间正好它被传递给被调用者的那一刻。但这只是一个猜测,而且是一个相当模糊的猜测。)

【讨论】:

    【解决方案2】:

    Matt 是对的,如果没有强引用,我找不到使用函数的方法。

    我刚刚发现您可以使用 var 使其更简洁 直接在函数内部编写闭包并不是很干净。

    class OnVarLeak : Leak {
    
        var value = 0
    
        override init() {
            super.init()
            NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "OnVarLeak"),
                                                   object: nil,
                                                   queue: nil,
                                                   using: doNothing)
        }
    
        var doNothing: (Notification) -> Void {
            return { [unowned self] notif in
                self.value += 1
            }
        }
    
        deinit {
            NotificationCenter.default.removeObserver(self)
        }
    }
    

    就像你没有强参考一样,你可以做“使用:doSomething)”。

    我仍然认为 Swift 编译让你使用函数而不是闭包是不安全的,因为它总是会在你的项目中留下内存泄漏。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多