Delegated - 自动实现闭包的 weak self

Delegated - 自动实现闭包的 weak self

IOS小彩虹2021-08-25 23:59:48180A+A-

Delegated - 自动 weak self

Closure,在日常代码中会经常使用到。使用它时,为了防止可恶的内存泄漏,要时常记得写 [weak self] 这样的代码。但对于程序员来说写这种模板代码是很枯燥的,所以, Delegated 就应运而生了。通过它注册过后的 Closure,可以自动的 weak self。下面就来看一下它的基本使用吧。

基本使用

它的使用很简单,通过下面两个步骤就可以实现自动的 weak self:

  • 使用 @Delegated 声明 Closure。
  • 使用 delegate() 函数来调用 Closure。

来看一个具体的例子:

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]!

实现原理

掌握了它的使用方法之后,下面来看一下它的实现原理。它的代码很简单,只有一个 Delegated.swift 文件,代码只有 410 行。

所有类的说明:

  • Delegated0:对应无返回值,无参数的 Closure。
  • Delegated1:对应无返回值,一个参数的 Closure。
  • Delegated2:对应无返回值,两个参数的 Closure。
  • Delegated3:对应无返回值,三个参数的 Closure。
  • ReturningDelegated0:对应有返回值,无参数的 Closure。
  • ReturningDelegated1:对应有返回值,一个参数的 Closure。
  • ReturningDelegated2:对应有返回值,两个参数的 Closure。
  • ReturningDelegated3:对应有返回值,三个参数的 Closure。

虽然代码包含上面 8 个类,但实质上只要理解了其中的任意一个类即可,因为其他的类只是参数和有无返回值的不同而已。

在这里,拿 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更详细的介绍可以看这里

接着,它通过定义 Input 来实现参数支持泛型,然后声明了 callback 属性来存储 Closure。对于 wrappedValue 和 projectedValue 则是重写的 @propertyWrapper 的内置参数。

接着,来看一下 extension 中的 delegate 函数。delegate 函数接受两个参数:

  • target:需要 weak 的对象。
  • callback:实际用到的 closure。

可以看到,在 delegate 函数体内,就是自动 weak self 的关键部分。对 callback 进行了重新赋值:

self.callback = { [weak target] input in
    // 通过这里实现自动 weak self
    guard let target = target else {
        return
    }
    return callback(target, input)
}

extension 中还有两个函数,它们的代码也很好理解:

  • manuallyDelegate:手动管理,即不使用自动 weak self。通过代码也可以看出它是直接给 callback 赋值,没有进行上面的 weak self 操作。
  • removeDelegate:移除代理。

至此,源码就分析完了。可以看到这个库的代码还是非常短小精悍的。

总结

  • 通过 @propertyWrapper 来进行模板代码封装。
  • 通过 callback 的重新赋值来实现自动 weak self。

点击这里复制本文地址 以上内容由权冠洲的博客整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!

支持Ctrl+Enter提交

联系我们| 本站介绍| 留言建议 | 交换友链 | 域名展示
本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除

权冠洲的博客 © All Rights Reserved.  Copyright quanguanzhou.top All Rights Reserved
苏公网安备 32030302000848号   苏ICP备20033101号-1
本网站由 提供CDN/云存储服务

联系我们