iOS 封装一个简易 UITableView 链式监听点击事件的功能思路与实现
废话开篇:RxSwift 对于其功能可以说是 swift 语言的高度封装了,但是它里面也用到了一些 OC 特性,比如交换方法实现。RxSwift 对于 UITableView 的点击事件就进行了二次封装,里面就交换了 respondsToSelector 方法及重写了消息转发机制下的 forwardInvocation,RxSwift 源码太复杂,因此,简单用 OC 写一个 demo,来理解一下 RxSwift 对于 UITableView 的点击事件的绑定。
1、实现原理
1、修改一个对象的 respondsToSelector 方法,当进来判断的 sel 是要求继续进行的方法时,返回 YES,这里很明显就是判断 tableView:didSelectRowAtIndexPath: 这个方法。这里注意的是,一个对象即使没有遵循代理协议而只要你实现了代理方法,那么,它也是可以正常执行的,代理协议的遵守只是方便开发通过编译器提示去实现代理方法的。
也就是说,让对象作为 UITableView 可执行 tableView:didSelectRowAtIndexPath: 方法的代理,但是不去实现这个代理方法。
2、修改一个对象的 forwardInvocation 方法,当一个对象调用方法出现没有实现的时候就要进行消息转发了,那么,在转发的时候截获 tableView:didSelectRowAtIndexPath: 方法的参数,进而转到别的对象去执行后续操作。
2、代码效果
当点击 cell 的时候,就通过上图中的 block 进行响应。这里其实从风格上有点类似 RX,但是,这里并没有对创建中对象的内存进行管理,下面有提到,一般 RxSwift 会有 Disposable 对象的返回,它就是来控制序列中创建的对象何时释放的类,可以用属性保存 DisposeBag,让序列与当前使用类生命周期一致,也可以在方法执行的最后面直接执行 dispose 销毁。
3、UITableView 的 rxRegistSelected 方法的实现
这里创建一个 UITableView 的分类:
UITableView+KDS.h
UITableView+KDS.m
这里圈出1的 KDSDelegateProxy 类就是 tableView:didSelectRowAtIndexPath: 代理方法处理类,并且圈出2为 UITableView 提供了一个 delegate,并在此之前调用 saveNeedDelegateSel 保存了需要消息转发的代理方法,这个方法后面解释。
到了这里,UITableView 就可以执行 rxRegistSelected 这个方法了,并且要为这个方法返回的 block1 传一个 UITableViewCell 点击事件响应的 block2,block2 是真正执行的点击事件具体实现,block1 仅为仿写 RAC 而写。
4、KDSDelegateProxy 对象的实现内容
KDSDelegateProxy.h
KDSDelegateProxy.m
4、KDSTableViewDelegateProxy
KDSTableViewDelegateProxy 是遵循 UITableViewDelegate 协议的对象,并为该对象保存外界传进来的 cell 点击的代理方法
5、总结与思考
RxSwift 远比上述复杂的多,换句话说个人能力有限说很难从一个百米高楼中去推断夯实地基的具体细节,因为毕竟不是参与施工人员,所以,这里也仅仅是个人思路。那么,说一下为什么没有类似 Disposable 对象,因为 demo 代码的的对象用的是 static 修饰的,如果不用全局变量,那么,作用域外对象就会销毁,代码也就无法运行了,所以,完全可以封装一个 WSLDisposable 类,在最里层的 block 里作为返回值,在最外层进行 dispose 销毁操作,来临时控制中间过程中的对象生命周期。或者封装类似 WSLDisposeBag,将它作为属性保存在例如控制器下,生命周期与当前 控制器一致。
好了,文章本意也仅分享,代码拙劣,大神勿笑。
作者:头疼脑胀的代码搬运工
链接:https://juejin.cn/post/7033679440613736456