NSTimer在tableView中的复用问题
来源:互联网 发布:人工智能仿生眼 编辑:程序博客网 时间:2024/05/21 14:04
之前,有位朋友,在写商品倒计时是,因为定时器在tableview上总是被复用,使改界面拖延了很久,最好找我写了个demo才解决。之后,还有不少iOS的朋友遇到类似复用的问题。这里只讲我这个demo中的关键代码及对复用的理解,demo的下载链接在文章最后。(如有不足请提出)
首先讲讲tableview的复用:cell在创建的时候,只会创建设备屏幕可见的cell个数,而不是按照你的数据源中的数据个数来创建的。然后反复使用这些cell,这样可以占用少量的内存来达到需要的效果。
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ static NSString * ID = @"3829472938"; TableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:ID]; if (!cell) { cell = [[TableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID]; } [cell setDataWithTitle:_array[indexPath.row]]; return cell;}这段代码,相信大家再熟悉不过了,但是不是所有人都理解这段代码。
static NSString * ID = @"3829472938"; TableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:ID];可以理解成为创建的cell一个标记
if (!cell) { cell = [[TableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ID]; }是加入cell为空,就创建新的cell,同时给占用这个内存的cell一个标记,然后再给cell赋值。而最重要的就是赋值这一步。因为,当你在拖动tableview的时候,加入该创建的cell都创建完了,那么就需要通过原有的cell来为需要的新的cell来赋值,通过赋值来改变cell上需要显示的数据,很多复用的问题就是因为没有及时的更新对应的数据。特别是在对待一些动态数据上,很多人在赋值一次以后,没有再次更新数据源,于是复用时,就重新赋上了数据源中的初始数据,造成显示数据不正确或者复用的问题。
下面是demo的核心代码:
控制器中定时器的创建
//创建定时器,控制数据源中的倒计时在controller中与cell的分类中一致-(void)viewDidAppear:(BOOL)animated{ [super viewDidAppear:animated]; //子线程创建定时器 [NSThread detachNewThreadSelector:@selector(multiThread) toTarget:self withObject:nil];}-(void)multiThread{ //确认定时器不是在主线程上时,创建定时器 //如果定时器要在子线程上跑起来,需要添加runloop if (![NSThread isMainThread]) { _timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(countdown:) userInfo:nil repeats:YES]; NSRunLoop * runloop = [NSRunLoop currentRunLoop]; [runloop addTimer:_timer forMode:NSRunLoopCommonModes]; [runloop run]; } }主要用来更新数据源对应的数据
-(void)countdown:(NSTimer *)timer{ //遍历数据源,如果对应下标的元素是NSNumber类型,就-1 for (int i = 0; i < _array.count; i++) { id obj = [_array objectAtIndex:i]; if ([obj isKindOfClass:[NSNumber class]]) { int a = [obj intValue]; a -- ; if (a <= -1) { [_array replaceObjectAtIndex:i withObject:@"被点击"]; }else{ [_array replaceObjectAtIndex:i withObject:@(a)]; } } }}自定义cell中button的定时器
//按钮点击事件-(void)clicked:(UIButton *)button{// button.selected = YES; if (_countDown==0) { _countDown = 20; } [_delegate takeTimeToControllerWithTime:_countDown Button:button]; //子线程创建定时器 [NSThread detachNewThreadSelector:@selector(multiThread) toTarget:self withObject:nil];}-(void)setDataWithTitle:(id)title{ //赋值时判断传进来的参数类型,如果是模型或字典就没必要这样判断了 if ([title isKindOfClass:[NSNumber class]]) { _countDown = [title intValue];// [self clicked:_button]; if (_countDown==0) { _countDown = 5;//自己改成120 } //子线程创建定时器 [NSThread detachNewThreadSelector:@selector(multiThread) toTarget:self withObject:nil]; }else{ if (_timer.valid) { //这里一定要判断,当title是字符串的时候,如果定时器还开着,一定要关,防止内存泄露和线程卡死,只要销毁定时器,runloop就会从线程上休眠 [self stop]; } [_button setTitle:title forState:UIControlStateNormal]; }}-(void)multiThread{ //确认定时器不是在主线程上时,创建定时器 //如果定时器要在子线程上跑起来,需要添加runloop if (![NSThread isMainThread]) { _timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(countdown:) userInfo:nil repeats:YES]; NSRunLoop * runloop = [NSRunLoop currentRunLoop]; [runloop addTimer:_timer forMode:NSRunLoopCommonModes]; [runloop run]; } }//定时器倒计时-(void)countdown:(id)send{ [_button setTitle:[NSString stringWithFormat:@"%d", _countDown] forState:UIControlStateNormal]; _countDown--; if (_countDown <= -1) { //当倒计时结束时,改变按钮标题 [_timer invalidate]; [_button setTitle:@"已点击" forState:UIControlStateNormal]; }}然后是最关键的一部,将点击的cell上的button改变的值存储到数据源中
//自定义cell的代理方法-(void)takeTimeToControllerWithTime:(int)time Button:(UIButton *)button{ //获取点击后的cell的下标,改变对应的数据源中的数据 TableViewCell *selectedCell = (TableViewCell *)button.superview.superview; NSIndexPath *index = [_tableView indexPathForCell:selectedCell]; [_array replaceObjectAtIndex:index.row withObject:@(time)]; }
详细代码请参考下面的demo:
点击打开链接
0 0
- NSTimer在tableView中的复用问题
- 解决NSTimer在TableView滑动中暂停问题
- tableview中的零散问题
- ios 倒计时在tableview或者collectionview中的重用问题
- tableview的复用问题
- iOS中的一些内存问题,block,NSTimer
- NSTimer问题
- 当tableview/scrollview滚动时定时器NSTimer / CADisplayLink停止响应问题
- 关于tableView复用的问题
- tableView的cell的复用问题
- NSTimer和NSRunLoop在子线程中的使用
- NSTimer和NSRunLoop在子线程中的使用
- tableView中的一些问题-新手必看
- iOS中的一些内存问题,block,NSTimer,dealloc
- iOS中的一些内存问题,block,NSTimer,dealloc
- 避免滑动tableView时NSTimer 暂停
- UITextField 在tableView中键盘弹出问题
- tableview 点击cell改变cell中的label.text的字体颜色,cell复用出现问题的解决方案
- android图片选取与调用系统裁剪
- 人脸识别之人脸检测(五)--adaboost总结,整理
- 12.6 小结
- abap面向对象的报表
- BAPI 更改交货单 & 更改捡配 'BAPI_OUTB_DELIVERY_CHANGE'
- NSTimer在tableView中的复用问题
- WAMP配置httpd.conf允许外部访问
- ALL_BUILD、ZERO_CHECK等详解
- RML制作PDF文档
- cgroup学习(五)——create new cgroup
- 13.1.1 直接路径插入
- 13.1.2 多表插入
- cgroup学习(六)——attach task
- ActionBar的使用以及向下兼容问题