Weakify 是一个 µframework,提供了一些常用的 weakify()
函数的变体。weakify()
主要用于在一个类中使用一个方法作为“闭包”值,该值由其他组件管理,但以一种防止内存泄漏的方式进行。
如果你定义一个(可以说是人为设计的)像这样的类
class Thing {
func doSomething() {
print("Something!")
}
var callback: () -> Void = {}
func registerCallback() {
callback = self.doSomething
}
}
let thing = Thing()
thing.registerCallback()
你将创建一个 retain cycle,并且 thing
永远不会被释放。每当你引用对象上的方法而不调用它时,绑定到该方法的类的实例将被该方法捕获,并在该方法的生命周期内保持。这是因为在 Swift 中,实例方法实际上是柯里化函数:你在类和实例上编写的实际方法会闭包(强烈地)引用 self,以便确保这些引用在方法的生命周期内都存在。
你可以通过在 registerCallback 方法中执行以下操作来解决这个问题
func registerCallback() {
callback = { [weak self] in
self?.doSomething()
}
}
这打破了 retain cycle。 但是,如果你要调用的方法的签名相同,则每次要这样做时都必须创建一个新的闭包,这有点麻烦,这就是 weakify()
的用武之地。 使用它,你可以像这样重写此方法
func registerCallback() {
callback = weakify(self, type(of: self).doSomething)
}
weakify()
使用静态方法引用将对象的实例与方法分离(你可以使用 Thing.doSomething
或 type(of: self).doSomething
静态地引用 doSomething
方法,其类型为 (Thing) -> () -> ()
)。 在此示例中,weakify
弱地将 self 应用于柯里化函数的第一个参数,返回一个类型为 () -> ()
的闭包,该闭包在被调用时,仅当 self
尚未被释放时才会执行 doSomething 方法(很像先前定义的手动弱捕获 self 的闭包)。
此库中有几个 weakify 变体可供您使用
func weakify <T: AnyObject, U>(_ owner: T, _ f: (T) -> () -> ()) -> (U) -> ()
func weakify <T: AnyObject, U>(_ owner: T, _ f: (T) -> () throws ->()) -> (U) throws -> ()
可以应用于任何不接受参数且不返回任何值的方法。 生成的闭包可以接受一个将被忽略的参数(在 NSNotificationCenter
之类的情况下很有用,当你不在乎 notification
参数时),或者该类型也可以表示 Void
,这意味着不需要输入参数。
func weakify <T: AnyObject, U>(_ owner: T, _ f: (T) -> (U) -> ()) -> (U) -> ()
func weakify <T: AnyObject, U>(_ owner: T, _ f: (T) -> (U) throws ->()) -> (U) throws -> ()
可以应用于接受一个参数且不返回任何值的方法,生成的闭包会镜像该方法。
func weakify <T: AnyObject, U, V>(_ owner: T, _ f: (T) -> (U) -> V) -> (U) -> V?
func weakify <T: AnyObject, U, V>(_ owner: T, _ f: (T) -> (U) throws -> V) -> (U) throws -> V?
可以应用于接受和返回某些内容的函数; 实际上是前两种情况的并集。
func weakify <T: AnyObject, U, V>(_ owner: T, _ f: (T) -> (U?) -> ()) -> (V) -> ()
func weakify <T: AnyObject, U, V>(_ owner: T, _ f: (T) -> (U?) throws -> ()) -> (V) throws -> ()
可以应用于接受可选值的函数。 生成的闭包可以具有完全不同的输入参数类型。 如果在调用时 owner
不为 nil
,则生成闭包的参数将使用 as?
运算符有条件地从 V
强制转换为 U
,并将该结果传递给原始函数(这就是为什么它必须接受可选值,以防强制转换失败)。
Weakify 可通过 CocoaPods 获得。 要安装它,只需将以下行添加到您的 Podfile 中
# Swift 3.x:
pod "Weakify", "~> 0.4.0"
# Swift 2.x:
pod "Weakify", "~> 0.2.3"
# Swift 1.2:
pod "Weakify", "~> 0.1.3"
Weakify 可以与 Carthage 集成。 将以下内容添加到您的 Cartfile 中以使用它
# Swift 3:
github "klundberg/Weakify" ~> 0.4.0
# Swift 2:
github "klundberg/Weakify" ~> 0.2.3
# Swift 1.2:
github "klundberg/Weakify" ~> 0.1.3
将以下行添加到您的 Package.swift
文件中的依赖项列表中(根据您的目标 Swift 版本更改版本)
.Package(url: "https://github.com/klundberg/weakify.git", versions:Version(0,4,0)..<Version(0,5,0)),
如果您不能使用 CocoaPods(例如,如果您仍然需要以 iOS 7 为最低目标),则推荐的安装方法是简单地手动将 weakify.swift 从 repo 复制到您的项目中。 您也可以选择将此 repo 作为 git submodule 引用,这是一个我留给您的练习。
Kevin Lundberg, kevin at klundberg dot com
如果您希望看到 Weakify 的其他变体,请随时提交 pull request! 请在任何更改中包含单元测试。
Weakify 在 MIT 许可证下可用。 有关更多信息,请参见 LICENSE 文件。