测试已测试 | ✓ |
语种语言 | SwiftSwift |
许可证 | MIT |
发布最后发布 | 2017年10月 |
SwiftSwift 版本 | 4.0 |
SPM支持 SPM | ✓ |
由Kevin Lundberg 维护。
Weakify 是一个 µ 框架,提供了一些常用的 weakify()
函数的变体。 weakify()
主要是一种能够将类的方法作为“闭包”值使用的方法,该值由其他组件管理,但同时又防止内存泄漏的发生。
如果您要定义一个(诚然是人为的)类,如下所示
class Thing {
func doSomething() {
print("Something!")
}
var callback: () -> Void = {}
func registerCallback() {
callback = self.doSomething
}
}
let thing = Thing()
thing.registerCallback()
您将创建一个保留周期,并且 thing
永远不会被释放。每次您引用一个对象上的方法却不调用它时,该方法所绑定类的实例将被方法捕获并持续到方法引用的生存期。这是因为 Swift 中实例方法是实际方法:您在类和实例上编写的实际方法会闭包引用 self(强引用)来确保这些引用的生存期至少与方法的生命周期一样长。
您可以在注册回调方法中这样做以解决这个问题
func registerCallback() {
callback = { [weak self] in
self?.doSomething()
}
}
这打破了保留周期。然而,如果要在具有相同签名的方法上这样做,就必须创建一个新闭包,这略显繁琐,这正是 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
,并将转换结果传递给原始函数(这就是为什么它必须接受可选值,以防转换失败)。
在您的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子模块引用,这留给您自行决定。
Kevin Lundberg,kevin at klundberg dot com
如果您希望增加Weakify的其他变体,请随时提交pull request!请为任何更改包括单元测试。
Weakify可在MIT许可下使用。有关更多信息,请参阅LICENSE文件。