一、前言
看过网易新闻、今日头条APP的都知道,他们的首页有很多频道,而且支持左右滑动来切换频道。作为一名iOS开发者,你肯定想过这个功能该怎么实现,其实挺简单,用UIScrollView内嵌UITableView就可以。但是当我们面临数量较多(10个左右)的频道时,如果一个频道用一个UITableView,那么你的APP很有可能在你左右滑动过程中内存飙升,最终崩溃...当然这并不是我们所想看到的。
二、思考解决方案
这个时候我想你第一个想到的解决方案应该是:复用!
没错,复用,就像UITableView里对Cell的复用一样,我们也要对ScrollView里的UITableView(更准确点说是ScrollView的每个page)进行复用。
,我先放出我实现的SliderPageReuseManager(github地址),然后再简单介绍一下我所实现的功能。
三、如何进行复用
我们都知道UITableView复用Cell时,我们只需要调用一个dequeueReusableCellWithIdentifier方法即可,这个方法会取出可复用的Cell返回给我们,当没有可复用的Cell时,会自动会我们实例化一个Cell,仿照这个思路,我制定了以下方案:
首先,定义一个复用池数组(reusePool),定义一个最大容量属性(capacity),当池子没有达到最大容量时,会实例化新的page,否则会取出数组中的第一个page进行复用。
其次,类似UITableViewCell的indexPath,为page扩展一个reuseKey属性来作为唯一标识,在进行实例化新page或者复用旧page前,需要先从复用池里进行一次遍历,如果找到一个reuseKey一样的page,则直接返回此page,相当于找到了原来缓存的page。
四、一些细节考虑
- 一般来说,这种多表滑动切换视图有2种实现方案,一种UIScrollView嵌套UITableView,直接在一个Controller里搞定,还有一种就是把page封装到一个独立的Controller里,通过childController的形式来管理,这种方式封装性较好,不同page通过不同的Controller管理,简洁易维护,我个人也是比较喜欢这种方式。因此,SliderPageReuseManager为UIViewController和UITableView都扩展了reuseKey属性。
- 为了满足不同page对应不同ViewController的需求,提供了一个registe接口供注册可复用的Class(可以是TableView或者ViewController),就像UITableView注册自定义Cell一样:)
- (void)registerClass:(Class)someClass forReuseIdentifier:(NSString *)identifier
- 项目中ViewController可能是纯代码,也可能是通过xib或者storyboard实例化的,为了能满足不同的实例化需求,为UIViewController扩展了reuseInstance方法,默认是alloc init方式,你可以根据你的需要重写此方法
/**
* 提供复用时实例化方法
* 可以是基本的[[self alloc] init],也可以通过storyboard实例化
*/
+ (instancetype)reuseInstance;
- 每一个page再被复用的时候,是需要做一些处理的,比如清除原来显示的数据(因为是不同的page,数据源不同),再加载新数据,所以扩展了一个属性:isReused,ViewController额外扩展了一个方法:
- (void)prepareForReuse;
复用的时候比较友好的处理流程是:优先获取本地缓存数据,如果无缓存再取服务端数据。
- 至于复用池容量capacity的选择,这个没有什么标准,只要遵循一个原则:不能太多(越多,内存需求越大),也不能过少(过少,左右滑动的时候会不连贯),好吧,说了等于没说...
五、附上效果图
六、结束语
文笔和能力有限,如果大家觉得有问题或者可改进的地方,欢迎指正,感激不尽!