2

将方法传递给采用闭包的函数时,我可以使用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) },则强引用消失了。

有任何想法吗?

4

2 回答 2

2

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

你不能。

只有内联定义的匿名函数(在使用时)才能具有捕获列表(例如[unowned self])。因此,只有匿名函数才能提供您所要求的功能。用简单定义的函数func无法做到这一点。

这只是关于 Swift 的事实。

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

于 2016-11-04T20:25:37.107 回答
0

马特是对的,如果没有强参考,我找不到使用函数的方法。

我刚刚发现您可以使用 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 编译让你使用函数而不是闭包是不安全的,因为它总是会在你的项目中留下内存泄漏。

于 2016-11-07T10:24:31.430 回答