delegate在iOS的开发中随处可见,不管是系统库还是第三方库都能看到delegate。在学习使用RxSwift的过程中发现如果项目组使用了RxSwift那如果再用delegate就和RxSwift的链式编程方式不相称了。解决办法就是对代理进行一层Rx封装。其中RxCocoa就是对Cocoa做了大量的封装。下面我们就自定义代理来演示最基本的对自定义代理进行Rx封装。
一、定义自己的代理
1.定义一个最简单的代理MyDelegate,这个代理里面有两个代理方法printNum和printStr,其中printStr是可选的。
@objc public protocol MyDelegate{
func printNum(num: Int)
@objc optional func printStr(str: String)
}
2.再定义一个类MyClass,MyClass类持有一个MyDelegate类型属性,还有两个方法,start和stop
class MyClass: NSObject {
public weak var delegate: MyDelegate?
var timer: Timer?
override init() {}
func start() {
timer = .init(timeInterval: 1, repeats: true, block: { _ in
self.delegate?.printNum(num: 1)
self.delegate?.printStr?(str: "这是字符串")
})
RunLoop.current.add(timer!, forMode: .default)
timer?.fire()
}
func stop() {
timer?.invalidate()
}
}
二、实现自定义代理的委托
1.DelegateProxy 是代理委托,我们可以将它看作是代理的代理。
2.DelegateProxy 的作用是做为一个中间代理,他会先把 delegate 对象保存一份,然后拦截 delegate的方法。
3.实现自定义代理的委托需要继承 DelegateProxy ,同时它还要遵守 DelegateProxyType 和 MyDelegate 协议。
class RxMyDelegateProxy: DelegateProxy<MyClass,MyDelegate>,DelegateProxyType,MyDelegate {
init(my: MyClass) {
super.init(parentObject: my, delegateProxy: RxMyDelegateProxy.self)
}
static func registerKnownImplementations() {
self.register { (parent) -> RxMyDelegateProxy in
RxMyDelegateProxy(my: parent)
}
}
static func currentDelegate(for object: MyClass) -> MyDelegate? {
return object.delegate
}
static func setCurrentDelegate(_ delegate: MyDelegate?, to object: MyClass) {
object.delegate = delegate
}
override func setForwardToDelegate(_ delegate: DelegateProxy<MyClass, MyDelegate>.Delegate?, retainDelegate: Bool) {
super.setForwardToDelegate(delegate, retainDelegate: true)
}
internal lazy var nums = PublishSubject<Int>()
func printNum(num: Int) {
_forwardToDelegate?.printNum(num: num)
self.nums.onNext(num)
}
deinit {
self.nums.onCompleted()
}
}
三、对MyClass类进行Rx扩展
我们对 MyClass 进行Rx 扩展,作用是将MyClass与前面创建的代理委托关联起来,将自定义的 delegate 方法转为可观察序列。
extension Reactive where Base: MyClass{
var delegate: DelegateProxy<MyClass,MyDelegate>{
return RxMyDelegateProxy.proxy(for: base)
}
var nums: Observable<Int>{
return RxMyDelegateProxy.proxy(for: base).nums.asObservable()
}
var strs: Observable<String>{
return delegate.methodInvoked(#selector(MyDelegate.printStr(str:))).map {
return $0[0] as! String
}
}
}
四、使用
let my: MyClass = MyClass()
my.start()
my.rx.nums.subscribe(onNext: { (num) in
print(num)
}).disposed(by: disposeBag)
my.rx.strs.subscribe(onNext: { (str) in
print(str)
}).disposed(by: disposeBag)