TableView相信只要是作iOS开发的就不会陌生,目前大多数iOS的app都是采用TabBar+NavigationBar+TableViewController这一主流框架,android
既然用的这么频繁,确定就会在开发过程当中碰到一些问题--好比屏幕掉帧、卡顿等现象。这些现象大幅度的下降了用户的性能体验,并提升了crash的频率。程序员
所以如何能优化好tableView就很是考验程序猿们的功底了。性能优化
本猿~啊呸,只要开发公司项目的时候就会遇到这类问题,当快速滑动tableView而且cell中有大量图片和其余控件须要加载时,就会出现严重掉帧(通常公司的项目当时大量采用xib如今逐渐用手写代码代替),有时还会crash。因为当时项目比较赶进度,因此没有时间去优化性能,这种状况直到功能基本完善为止,花了大量功夫进行性能优化。
接下来我会根据tableView的delegate以及dataSource方法的执行顺序进行一步一步的讲解。服务器
首先当一个tableView须要显示内容的时候,首先会发送网络请求,向服务器请求数据,而后将数据转为咱们可使用的model后进行reload操做,接下来会向delegate和网络
dataSource请求数据。这时候会先调用- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
这个方法(假设section为1)。根据app
model获取cell的行数而后调用-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
,根据model计算出cell的高度。因为框架
tableView是继承自scrollView,因此tableView也会有contentSize属性。它的contentSize取决于全部cell的高度和。和scrollView有一点不一样,tableView只会管理可视的cell高度,这样作的目的是避免没必要要的性能开销。异步
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
这个代理方法的实现,在可见的页面是会重复绘制页面的,因此绝大部分人都会在这里作一些代码处理
好比:oop
static NSString *CellIdentifier = @"LazyTableCell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
很常规的,防止cell对象无限的被建立,等同于android里面适配器的方法性能
以上举例代码是可让cell被重复使用,通常大概只会在可见页面部分的几个cell会被建立下,其余的所有重复使用前面已经有的cell对象,到时候只要填充数据就能够了
那么仅仅只是如此,恐怕如今的cell自定义的页面不仅是文本那么简单,多多少少都会带有一些图片吧,当你下滑时候是否发现有那么一点点的卡顿现成,特别是网络很差,并且仍是在iPhone4上跑的就会更明显了
那么在cell里面异步加载图片是个程序员都会想到,可是若是你给每一个循环对象都加上异步加载,而且下滑的时候,这一操做将会被执行,虽然是异步,可是一个app里面的线程过多也会卡顿的,特别是在下滑操做的时候给每一个图片进行异步加载。
那么这里能够利用UIScrollViewDelegate代理很好的解决这问题:
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
能够识别tableview禁止或者减速滑动结束的时候进行异步加载图片。
如下方法来执行异步加载操做:
//获取可见部分的对象 NSArray *visiblePaths = [self.tableView indexPathsForVisibleRows]; for (NSIndexPath *indexPath in visiblePaths) { //获取的dataSource里面的对象,而且判断加载完成的不须要再次异步加载 <code> }
同时在cell绘制中也作限制
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath if (self.tableView.dragging == NO && self.tableView.decelerating == NO) { //开始异步加载图片 <code> }
tableview 中止滑动的时候开始异步加载图片
最后也别忘记在内存紧张的状况下释放调全部的异步线程,以保证的你的app不会被系统强制关闭
- (void)didReceiveMemoryWarning{ // 释放调异步加载图片的线程以及全部图片资源对象 <code> }
还有千万别忘记销毁的时候手动把全部的使用到的代理设置nil。
还有一个利用线程和Runloop延迟加载图片的新思路:
[self.avatarImageView performSelector:@selector(serImage:) withObjetc:downloadedImage afterDelay:0 inModes:@[NSDefaultRunLoopMode]] + (NSThread *)networkRequestThread { static NSThread *_networkRequestThread = nil; static dispatch_once_t oncePredicate; dispatch_once(&oncePredicate, ^{ _networkRequestThread = [[NSThread alloc] initWithTarget:self selector:@selector(networkRequestThreadEntryPoint:) object:nil]; [_networkRequestThread start]; }); return _networkRequestThread;