iOS11.0中的 tableView
在iOS11中如果不实现-tableView: viewForHeaderInSection:和-tableView: viewForFooterInSection:
则-tableView: heightForHeaderInSection:和- tableView: heightForFooterInSection:不会被调用
导致它们都变成了默认高度,这是因为tableView在iOS11默认使用Self-Sizing,在创建 tableView 的时候,添加如下代码
if (@available(iOS 11.0, *)) {
UITableView.appearance.estimatedRowHeight = 0;
UITableView.appearance.estimatedSectionFooterHeight = 0;
UITableView.appearance.estimatedSectionHeaderHeight = 0;
UITableView.appearance.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
} else {
self.automaticallyAdjustsScrollViewInsets = NO;
}
UITableView 点一下才刷新列表
异步读取数据,在异步中刷新数据(reloadData)
可能在比较慢的Mac上的模拟器上跑的时候没有什么问题,但是在真机调试的时候就会出现bug.比如,打开app的时候不自动显示数据列表,点击一下,才会出现数据列表.
很有可能就是出现在子线程中reloadData.我们要把该过程放入主线程中:
dispatch_async(dispatch_get_main_queue(), ^{
self.dataSourceArray= a new Array;
[self.tableView reloadData];
});
原理解释:
在tableView的dataSource被改变 和 tableView的reloadData被调用之间有个时间差,而正是在这个期间,tableView的delegate方法被调用,如果新的dataSource的count小于原来的dataSource count,crash就很有可能发生了。
Always change the dataSource 'and(注意这个and)' reloadData in the mainThread. What's more, reloadData should be called 'immediately' after the dataSource change.
If dataSource is changed but tableView's reloadData method is not called immediately, the tableView may crash if it's in scrolling.
Crash Reason: There is still a time gap between the dataSource change and reloadData. If the table is scrolling during the time gap, the app may Crash!!!!
UITableView的复用
都知道UITableView 会根据复用的ID
来对UITableViewCell进行复用,防止 UITableView 中不断创建 cell,导致内存暴涨.
大致原理:
比如:在当前界面的数组dataArr.count = 20,但是当前界面初始最多只能显示7个(底部显示一点点的也算),这7个 cell 就是刚运行的时候创建的,这些创建的 cell 会放到缓存池中.再往下滑动,或者下滑了之后再往上滑,会根据你事先设置的reuseIdentifier
到缓存池中去取 cell,然后对 cell 上的控件重新赋值,显示出来代码实践
// 定义一个 tableView 控件
@property(nonatomic,strong)UITableView *tableView;
// 对tableView 进行懒加载
-(UITableView* )tableView{
if (!_tableView) {
// UITableViewStyleGrouped
_tableView = [[UITableView alloc]initWithFrame:CGRectMake(0, 0, CIO_SCREEN_WIDTH, CIO_SCREEN_HEIGHT)];
_tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
_tableView.delegate = self;
_tableView.dataSource = self;
_tableView.backgroundColor = [UIColor whiteColor];
}
return _tableView;
}
tableView 创建完毕,就是遵循实现 datasource ,delegate 的代理方法.
- 如果创建的时候没有对该tableView的重用标志符设置,可以这样处理
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *identifier = @"cellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
}
cell.textLabel.text = [NSString stringWithFormat:@"section -- %ld, row -- %ld", indexPath.section, indexPath.row];
cell.textLabel.textColor = [UIColor blueColor];
cell.backgroundColor = [UIColor lightGrayColor];
return cell;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
// 如果缓存池有足够的 cell 了,可以通过重用标志符直接复用,不用在if (!cell1)重新创建了
UITableViewCell *cell1 = [tableView dequeueReusableCellWithIdentifier:@"cellOne"];
if (!cell1) {
// 这里都是初始化后创建的那些,就是需要创建的那7个
cell1 = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cellOne"];
cell1.selectionStyle = UITableViewCellSelectionStyleNone;
}
return cell1;
}
- 如果不想用上述办法,还可以在创建tableView的时候加上:
// 为 tableView 注册一个重用标志符为 cellOne 的 UITableViewCell
[_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cellOne"];
然后在代理方法中,直接调用重用即可
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
// 如果缓存池有足够的 cell 了,可以通过重用标志符直接复用,不用在if (!cell1)重新创建了
UITableViewCell *cell1 = [tableView dequeueReusableCellWithIdentifier:@"cellOne"];
cell1.selectionStyle = UITableViewCellSelectionStyleNone;
cell1.selectionStyle = UITableViewCellSelectionStyleNone;
return cell1;
}
- 可以自己编写代码,然后断点进行调试,会对2种方法有更深入的了解
设置TableViewCell 分割线全屏宽度
- 在自定义的 TableViewCell 中加入一下代码
if ([self respondsToSelector:@selector(setSeparatorInset:)]) {
[self setSeparatorInset:UIEdgeInsetsZero];
}
if ([self respondsToSelector:@selector(setLayoutMargins:)]) {
[self setLayoutMargins:UIEdgeInsetsZero];
}
if([self respondsToSelector:@selector(setPreservesSuperviewLayoutMargins:)]){
[self setPreservesSuperviewLayoutMargins:NO];
}
- 使用系统的 UITableViewCell 时,也可以在创建cell 的 datasource 方法中加入以下代码,同样的效果
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell =
[tableView dequeueReusableCellWithIdentifier:@"myCell"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:@"myCell"];
}
if ([cell respondsToSelector:@selector(setSeparatorInset:)]) {
[cell setSeparatorInset:UIEdgeInsetsZero];
}
if ([cell respondsToSelector:@selector(setLayoutMargins:)]) {
[cell setLayoutMargins:UIEdgeInsetsZero];
}
if([cell respondsToSelector:@selector(setPreservesSuperviewLayoutMargins:)]){
[cell setPreservesSuperviewLayoutMargins:NO];
}
}