iOS11.0中的 tableView
在iOS11中如果不實現(xiàn)-tableView: viewForHeaderInSection:和-tableView: viewForFooterInSection:
則-tableView: heightForHeaderInSection:和- tableView: heightForFooterInSection:不會被調(diào)用
導(dǎo)致它們都變成了默認(rèn)高度别洪,這是因為tableView在iOS11默認(rèn)使用Self-Sizing,在創(chuàng)建 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 點一下才刷新列表
異步讀取數(shù)據(jù),在異步中刷新數(shù)據(jù)(reloadData)
可能在比較慢的Mac上的模擬器上跑的時候沒有什么問題,但是在真機調(diào)試的時候就會出現(xiàn)bug.比如,打開app的時候不自動顯示數(shù)據(jù)列表,點擊一下,才會出現(xiàn)數(shù)據(jù)列表.
很有可能就是出現(xiàn)在子線程中reloadData.我們要把該過程放入主線程中:
dispatch_async(dispatch_get_main_queue(), ^{
self.dataSourceArray= a new Array;
[self.tableView reloadData];
});
原理解釋:
在tableView的dataSource被改變 和 tableView的reloadData被調(diào)用之間有個時間差钟鸵,而正是在這個期間映砖,tableView的delegate方法被調(diào)用,如果新的dataSource的count小于原來的dataSource count郊楣,crash就很有可能發(fā)生了。
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的復(fù)用
都知道UITableView 會根據(jù)復(fù)用的ID
來對UITableViewCell進行復(fù)用,防止 UITableView 中不斷創(chuàng)建 cell,導(dǎo)致內(nèi)存暴漲.
大致原理:
比如:在當(dāng)前界面的數(shù)組dataArr.count = 20,但是當(dāng)前界面初始最多只能顯示7個(底部顯示一點點的也算),這7個 cell 就是剛運行的時候創(chuàng)建的,這些創(chuàng)建的 cell 會放到緩存池中.再往下滑動,或者下滑了之后再往上滑,會根據(jù)你事先設(shè)置的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 創(chuàng)建完畢,就是遵循實現(xiàn) datasource ,delegate 的代理方法.
- 如果創(chuàng)建的時候沒有對該tableView的重用標(biāo)志符設(shè)置,可以這樣處理
- (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 了,可以通過重用標(biāo)志符直接復(fù)用,不用在if (!cell1)重新創(chuàng)建了
UITableViewCell *cell1 = [tableView dequeueReusableCellWithIdentifier:@"cellOne"];
if (!cell1) {
// 這里都是初始化后創(chuàng)建的那些,就是需要創(chuàng)建的那7個
cell1 = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cellOne"];
cell1.selectionStyle = UITableViewCellSelectionStyleNone;
}
return cell1;
}
- 如果不想用上述辦法,還可以在創(chuàng)建tableView的時候加上:
// 為 tableView 注冊一個重用標(biāo)志符為 cellOne 的 UITableViewCell
[_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cellOne"];
然后在代理方法中,直接調(diào)用重用即可
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
// 如果緩存池有足夠的 cell 了,可以通過重用標(biāo)志符直接復(fù)用,不用在if (!cell1)重新創(chuàng)建了
UITableViewCell *cell1 = [tableView dequeueReusableCellWithIdentifier:@"cellOne"];
cell1.selectionStyle = UITableViewCellSelectionStyleNone;
cell1.selectionStyle = UITableViewCellSelectionStyleNone;
return cell1;
}
- 可以自己編寫代碼,然后斷點進行調(diào)試,會對2種方法有更深入的了解
設(shè)置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];
}
- 使用系統(tǒng)的 UITableViewCell 時,也可以在創(chuàng)建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];
}
}