一 重用机制
1 问题
UITablevView是开发中最常用的实现滚动列表的方案之一, 列表的具体内容载体由UITablevViewCell, 负责一个列表可能有成千上万个cell,然而iOS设备的内存是有限的,无限制的创建cell将会耗尽设备内存进而导致程序crash.
苹果为了解决此问题, 设计出一种既能展示大量数据又能节省内存的机制即重用机制.
2 原理
UITableView内部维护了一个重用缓存池队列, 当屏幕上cell移动出屏幕后, 系统自动把它放入重用池中, 当dataSource下一条数据要求呈现时, 系统会去重用池中查找是否有可重用对象, 如果有则拿出复用, 没有则走创建流程. 同时, 为了避免避免列表中有多种自定义UITableViewCell, 苹果通过绑定重用标识符(identifier)来查找对应的cell类型.
在这里查看官方文档
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
//如果重用池当中没有可重用的cell,那么创建一个cell
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
}
这里A1到A7视为同一个标识符,虚线是可视区域,当A1滑出可视区域的时候会放入重用池A,A7根据标识符从备用池取出一个可重用的cell,这样就达到了重用的一个目的
3 模拟重用池
字母索引条的小demo
创建使用中和重用池中的对象集合
_waitUsedQueue = [NSMutableSet set];
_usingQueue = [NSMutableSet set];
取出一个可重用的视图
- (UIView *)dequeueReusableView{
UIView *view = [_waitUsedQueue anyObject];
if (view == nil) {
return nil;
} else {
// 从重用池队列中移除,添加到使用队列
[_waitUsedQueue removeObject:view];
[_usingQueue addObject:view];
return view;
}
}
添加视图到重用池
- (void)addUsingView:(UIView *)view {
if (view == nil) {
return;
}
[_usingQueue addObject:view];
}
将当前所有视图移动到重用池中
- (void)reset{
UIView *view = nil;
while ((view = [_usingQueue anyObject])) {
// 从使用中队列移除
[_usingQueue removeObject:view];
// 加入等待使用的队列
[_waitUsedQueue addObject:view];
}
}
二 数据源同步
1 问题
删除列表一条数据, 崩溃!
本质是tableView在多线程的情况下修改或者访问数据源后的如何同步?
[self.dataSource removeObjectAtIndex:indexPath.row];
[self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
2 解决方案
2.1 并发访问&数据拷贝
- 用户删除一条数据, reloadUI
- 异步通知子线程数据同步
- 异步数据回调, reloadUI
- 缺点: 拷贝操作, 占用大量内存, 浪费CPU性能
2.2 串行访问
- 异步串行队列做网络请求, 数据解析, 预排版
- 用户删除数据
- 异步通知子线程数据同步
- 回调, reloadUI
我是个写代码的小学生, 如有不足, 万望不吝指教