前言
在Swift中我们使用闭包(Callback)的时候经常要写 [weak self] or [unowned self].
而且你不写, 系统也不会提示你, 这就很容易出现循环引用. ( /(ㄒoㄒ)/~~ 表示本人已经忘记无数次了. )
所以为了避免这种情况, 自然而然就有了这个库 Delegated .
使用示例
一般闭包示例
// 声明
typealias XQCallback = (String) -> ()
private var callback: XQCallback?
// 调用闭包
callback(str)
// 外部给闭包赋值
self.callback { [unowned self] (value) in
print(self, value)
}
Delegated 示例
// 声明, 并创建结构体 <inputValue, outputValue>
// inputValue: 调用闭包传出去的值
// outputValue: 闭包内return出来的值
var callback = Delegated<String, Void>.init()
// 调用闭包
callback.call("inputValue")
// 外部给闭包赋值
callback.delegate(to: self) { (self, inputValue) in
print(self, inputValue)
}
使用起来, 和原来的闭包写的差不多, 但是这边是把 self 作为参数传进去, 避免了忘写的尴尬.
源码解析
整个库就一个文件, 而且代码很少, 我们一个一个方法来解析.
public struct Delegated<Input, Output> {
// 赋值闭包, 无需自己写weak
// !!!这个是主要方法, 看明白这个就可以了
public mutating func delegate<Target : AnyObject>(to target: Target,
with callback: @escaping (Target, Input) -> Output) {
// 赋值callback, 并且weak传入的target值 (这里就把原本我们要写的weak做了)
self.callback = { [weak target] input in
guard let target = target else {
return nil
}
return callback(target, input)
}
}
// 调用callback
public func call(_ input: Input) -> Output? {
return self.callback?(input)
}
// 声明闭包
private(set) var callback: ((Input) -> Output?)?
// 是否已经赋值callback true已赋值, false未赋值
public var isDelegateSet: Bool {
return callback != nil
}
public init() { }
}
// 这个扩展用到了一个 where Output == Void, 很巧妙.
// 这样的话, 传入output是Void类型, 调用闭包时, 就会自动为无返回值.
extension Delegated where Output == Void {
// 调用闭包
public func call(_ input: Input) {
self.callback?(input)
}
}
// 这个扩展不需要看太多, 我大致标明一下函数含义就行
extension Delegated {
// 赋值闭包, 需要自己写weak
public mutating func stronglyDelegate<Target : AnyObject>(to target: Target,
with callback: @escaping (Target, Input) -> Output) {}
// 赋值闭包, 需要自己写weak
public mutating func manuallyDelegate(with callback: @escaping (Input) -> Output) {}
// 删除当前已赋值的闭包
public mutating func removeDelegate() {}
}
虽然代码量少, 但是这个思路真的不错, 胜在实用性.
不过这个第三方还有几个点没解决
- 没提供能动态多个weakTarget
- input只有一个参数.
不过这都是小事,明白原理之后, weakTarget可以自己照着写, 多写几个就行.(应该也不会用很多个吧 ✧(≖ ◡ ≖) )
而参数问题, 我们可以不写多几个函数, 我们可以直接用元组, 如下:
// typealias 一个元组类型
typealias Login = (acc: String, pwd: String)
// Delegated 声明并初始化
var callback = Delegated<Login, Void>.init()
// 点击登录按钮
@IBAction func respondsToBtn(_ sender: Any) {
// Delegated 调用闭包
self.callback.call(("账号", "密码"))
}
// 外部赋值闭包
self.tView.callback.delegate(to: self) { (self, info) in
print("acc:", info.acc, "\npwd:", info.pwd)
}
这样一个参数也无所谓了
示例Demo
写了一个使用示例demo, 两个页面的跳转, 按钮的点击是一个view传到viewController.
展示了普通闭包和使用Delegated的区别
![](https://img.haomeiwen.com/i4904781/fc9ef4ad0e7ff879.gif)
使用普通闭包回跳.
真的容易忘写 /(ㄒoㄒ)/~~ ,自从写Swift以来, 不知道忘写多少次了.
使用Delegated回跳
网友评论