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)
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对毛票票的支持。