RxSwift实现替换delegate的方法示例
目标
最近写项目,写到需要为自己写的一个控件添加rx订阅方式的案例。
目前有一个代理:
//代理方式获取结果
@objcpublicprotocolZZPhotoPickerControllerDelegate:NSObjectProtocol{
@objcoptionalfuncphotoPickerController(_photoPickerController:ZZPhotoPickerController,didSelectassets:[Any])
}
需要写一个能够实现下边这种方式的扩展
photoPickerController.rx.assetsSelected.subscribe(onNext:{assetsin
//dosomething
}
思路
刚开始完全摸不着头脑。后来想到Rx写了对UICollectionViewDelegate的扩展:
collectionView.rx.itemSelected.subscribe(onNext:{indexPathin
//dosomething
}
跟我的需求是一样的。
于是就去看itemSelected的源代码:
///Reactivewrapperfor`delegate`message`collectionView(_:didSelectItemAtIndexPath:)`. publicvaritemSelected:ControlEvent{ letsource=delegate.methodInvoked(#selector(UICollectionViewDelegate.collectionView(_:didSelectItemAt:))) .map{ain returntrycastOrThrow(IndexPath.self,a[1]) } returnControlEvent(events:source) }
souce是一个Observable,由delegate.methodInvoked产生。delegate是什么delegate?为什么会有methodInvoked方法?于是继续点进去。
extensionReactivewhereBase:UIScrollView{
///...这部分代码省略不用看
///Reactivewrapperfor`delegate`.
///
///Formoreinformationtakealookat`DelegateProxyType`protocoldocumentation.
publicvardelegate:DelegateProxy{
returnRxScrollViewDelegateProxy.proxy(for:base)
}
///...后面的代码暂时也不用看
}
可以看到delegate是一个DelegateProxy
openclassRxScrollViewDelegateProxy :DelegateProxy,DelegateProxyType ,UIScrollViewDelegate{ ///Typedparentobject. publicweakprivate(set)varscrollView:UIScrollView? ///-parameterscrollView:Parentobjectfordelegateproxy. publicinit(scrollView:ParentObject){ self.scrollView=scrollView super.init(parentObject:scrollView,delegateProxy:RxScrollViewDelegateProxy.self) } //Registerknownimplementations publicstaticfuncregisterKnownImplementations(){ self.register{RxScrollViewDelegateProxy(scrollView:$0)} self.register{RxTableViewDelegateProxy(tableView:$0)} self.register{RxCollectionViewDelegateProxy(collectionView:$0)} self.register{RxTextViewDelegateProxy(textView:$0)} } ///...后面的感觉没什么关系,先不看 }
可以看到它其实是一个DelegateProxy
现在脑海中大概有一个模糊的思路:我们要先创建一个纽带delegateProxy对象,然后在目标类的rx扩展中创建一个delegateProxy实例,最后在我们的assetsSelected事件流中用这个delegateProxy的methodInvoked截获delegate中的目标方法,并生成可订阅的Observable返回给controlEvent,这样链接打通。
开动
首先创建一个RxPhotoPickerControllerDelegateProxy
classRxPhotoPickerControllerDelegateProxy:DelegateProxy,DelegateProxyType,ZZPhotoPickerControllerDelegate{ ///Typedparentobject. publicweakprivate(set)varphotoPickerController:ZZPhotoPickerController? ///-parameterscrollView:Parentobjectfordelegateproxy. publicinit(photoPickerController:ParentObject){ self.photoPickerController=photoPickerController super.init(parentObject:photoPickerController,delegateProxy:RxPhotoPickerControllerDelegateProxy.self) } staticfuncregisterKnownImplementations(){ self.register{RxPhotoPickerControllerDelegateProxy(photoPickerController:$0)} } //把上面的写好后,编辑器会提示你需要实现一下两个方法,一个是获取,一个是设置,所以很好理解该在方法里实现什么。 staticfunccurrentDelegate(forobject:ZZPhotoPickerController)->ZZPhotoPickerControllerDelegate?{ returnobject.zzDelegate } staticfuncsetCurrentDelegate(_delegate:ZZPhotoPickerControllerDelegate?,toobject:ZZPhotoPickerController){ object.zzDelegate=delegate } }
然后给目标的rx扩展写一个delegateProxy实例:
extensionReactivewhereBase:ZZPhotoPickerController{
publicvarzzDelegate:DelegateProxy{
returnRxPhotoPickerControllerDelegateProxy.proxy(for:base)
}
}
最后写我们的assetsSelected:
extensionReactivewhereBase:ZZPhotoPickerController{
varassetsSelected:ControlEvent<[Any]>{
letsource:Observable<[Any]>=self.zzDelegate.methodInvoked(#selector(ZZPhotoPickerControllerDelegate.photoPickerController(_:didSelect:))).map{ain
returna[1]as![Any]
}
returnControlEvent.init(events:source)
}
}
要注意里面有个方法castOrThrow,这个方法rx并没有开放出来,是个内部方法,如果照着写报错。可以研究出该方法只是一个类型推断而已,所以可以简单写。
完成
然后就可以愉快的去对assetsSelected进行订阅了。
vc.rx.assetsSelected.subscribe(onNext:{(assets)in
//dosomething
}).disposed(by:self.disposeBag)
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对毛票票的支持。