performselector实现原理(ios UITableView实现图片懒加载)

开发中常用到UITableView加载大量数据,需要性能优化问题,本文通过UITableView加载大量图片案例来说明。

  1. 实现方式一:基于可见cell视图加载图片

实现原理: tableView加载可见的cell图片(手指未拖动和减速动画快结束才加载)

(1)绑定cell时,判断手指未拖动和减速动画快结束,才加载图片

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cellId"]; if (cell==nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cellId"]; } ImageRecord *record = self.dataList[indexPath.row]; if (record.image) { cell.imageView.image = record.image; }else{ cell.imageView.image = [UIImage imageNamed:@"head"]; //手指未拖动和减速动画快结束 if (!tableView.dragging && !tableView.decelerating) { //加载图片 [self downloadImage:indexPath]; } } cell.textLabel.text = record.title; return cell; }


(2)tableview停止滚动,开始加载图像,实现以下代理方法

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { //加载可见cell图片 [self showVisibleCellImage]; }


(3)tableView停止拖拽,没有减速动画,实现以下代理方法

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate { //加载可见cell图片 if (!decelerate) { [self showVisibleCellImage]; } }


(4)退出界面时,取消任务下载

- (void)viewDidDisappear:(BOOL)animated{ [super viewDidDisappear:animated]; //取消下载图片任务 NSArray *values = self.tasksDic.allValues; [values makeObjectsPerformSelector:@selector(cancel)]; }

2.实现方式二:基于runloop实现图片渲染

原理:创建定时器,获取当前线程runloop ,并监听runloop将进入休眠事件,处理图片加载,runloop每次循环时,只加载一次图片渲染。

(1)创建定时器

// 让runloop一直转起来 self.timer = [NSTimer scheduledTimerWithTimeInterval:0.0001 target:self selector:@selector(timerMethod) userInfo:nil repeats:YES];

- (void)timerMethod { // 添加timer才开启block任务的执行,不然数组tasks会因为添加30个而导致数组中保存的仅仅是最后五个,TableView一出来cell图片没显示,因为就没有对应的任务 self.display = YES; }

(2)通过当前定时器的线程的runloop, 监听runloop将进入休眠事件

// 创建观察者 // 拿到当前的runloop CFRunLoopRef runloop = CFRunLoopGetCurrent(); // 定义一个上下文 CFRunLoopObserverContext context = {0, (__bridge void *)(self), NULL, NULL, NULL}; // 创建一个观察者 _defaulModeObserver = CFRunLoopObserverCreate(NULL, kCFRunLoopBeforeWaiting, YES, 0, &Callback, &context); CFRunLoopAddObserver(runloop, _defaulModeObserver, kCFRunLoopCommonModes); CFRelease(runloop);

static void Callback(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) { SecondViewController *vc = (__bridge SecondViewController *)info; //无任务 退出 if (vc.tasks.count == 0) { return; } if (vc.display) { //从数组中取出任务 RunloopBlock task = vc.tasks.firstObject; if (task) { task(); //执行完任务之后移除任务 [vc.tasks removeObjectAtIndex:0]; } } }

(3)绑定cell时,添加加载图片任务

performselector

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { ImageCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifierID forIndexPath:indexPath]; NSInteger row = indexPath.row; cell.imageView1.image = nil; cell.imageView2.image = nil; cell.imageView3.image = nil; //添加任务1 [self addTask:^{ dispatch_async(dispatch_get_global_queue(0, 0), ^{ UIImage *img = [UIImage imageNamed:[NSString stringWithFormat:@"%ld",(long)(row%3)]]; dispatch_async(dispatch_get_main_queue(), ^{ cell.imageView1.image = img; }); }); }]; //添加任务2 [self addTask:^{ dispatch_async(dispatch_get_global_queue(0, 0), ^{ UIImage *img = [UIImage imageNamed:[NSString stringWithFormat:@"%ld",(long)(row%3)]]; dispatch_async(dispatch_get_main_queue(), ^{ cell.imageView2.image = img; }); }); }]; //添加任务3 [self addTask:^{ dispatch_async(dispatch_get_global_queue(0, 0), ^{ UIImage *img = [UIImage imageNamed:[NSString stringWithFormat:@"%ld",(long)(row%3)]]; dispatch_async(dispatch_get_main_queue(), ^{ cell.imageView3.image = img; }); }); }]; return cell; }

添加任务方法:

- (void)addTask:(RunloopBlock)task { if (self.display) { // 判断当前待执行的代码块是否超出最大代码块数 if (self.tasks.count > self.maxQueueLength) { // 干掉最开始的代码块 [self.tasks removeObjectAtIndex:0]; } } // 将代码块添加到可变数组中 [self.tasks addObject:task]; }

3.懒加载图片demo源代码下载

下载地址: https://gitee.com/rang/tableview_lazy-demo.git

您可以还会对下面的文章感兴趣

使用微信扫描二维码后

点击右上角发送给好友