Closure,在平常代码中会常常使用到。使用它时,为了防止可恶的内存泄漏,要时常记得写 [weak self]
这样的代码。但对于程序员来讲写这种模板代码是很枯燥的,因此, Delegated 就应运而生了。经过它注册事后的 Closure,能够自动的 weak self。下面就来看一下它的基本使用吧。git
它的使用很简单,经过下面两个步骤就能够实现自动的 weak self:程序员
来看一个具体的例子:github
final class TextField {
// 第一步:使用 @Delegated 声明 Closure。
@Delegated var didUpdate: (String) -> ()
}
// 第二步:使用 delegate() 函数来调用 Closure。
textField.$didUpdate.delegate(to: self) { (self, text) in
// `self` is weak automatically!
self.label.text = text
}
复制代码
经过上面的两步就实现了自动 weak self,没有循环引用,没有内存泄漏,没有 [weak self]
!🎉swift
掌握了它的使用方法以后,下面来看一下它的实现原理。它的代码很简单,只有一个 Delegated.swift 文件,代码只有 410 行。api
全部类的说明:markdown
虽然代码包含上面 8 个类,但实质上只要理解了其中的任意一个类便可,由于其余的类只是参数和有无返回值的不一样而已。app
在这里,拿 Delegated1 来举例说明一下它的实现原理。函数
@propertyWrapper
public final class Delegated1<Input> {
public init() { self.callback = { _ in } }
private var callback: (Input) -> Void
public var wrappedValue: (Input) -> Void { return callback }
public var projectedValue: Delegated1<Input> {
return self
}
}
public extension Delegated1 {
func delegate<Target: AnyObject>(
to target: Target,
with callback: @escaping (Target, Input) -> Void
) {
self.callback = { [weak target] input in
guard let target = target else {
return
}
return callback(target, input)
}
}
func manuallyDelegate(with callback: @escaping (Input) -> Void) {
self.callback = callback
}
func removeDelegate() {
self.callback = { _ in }
}
}
复制代码
首先,来分析一下 Delegated1 类。能够看到它使用了 @propertyWrapper 关键字来修饰,@propertyWrapper 的做用简单来讲就是用来封装日常的模板代码。关于@propertyWrapper更详细的介绍能够看这里。oop
接着,它经过定义 Input 来实现参数支持泛型,而后声明了 callback 属性来存储 Closure。对于 wrappedValue 和 projectedValue 则是重写的 @propertyWrapper 的内置参数。spa
接着,来看一下 extension 中的 delegate 函数。delegate 函数接受两个参数:
能够看到,在 delegate 函数体内,就是自动 weak self 的关键部分。对 callback 进行了从新赋值:
self.callback = { [weak target] input in
// 经过这里实现自动 weak self
guard let target = target else {
return
}
return callback(target, input)
}
复制代码
extension 中还有两个函数,它们的代码也很好理解:
至此,源码就分析完了。能够看到这个库的代码仍是很是短小精悍的。