美文网首页iOS Dev留着看iOS开发
UITableView滚动到底部时崩溃的解决方法

UITableView滚动到底部时崩溃的解决方法

作者: uniapp | 来源:发表于2016-08-24 16:05 被阅读2310次

    项目中的直播界面,要求客户端发送信息后,tableView自动滚动到最后一行.
    UITableView中有滚动的方法:

    - (void)scrollToRowAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(UITableViewScrollPosition)scrollPosition animated:(BOOL)animated
    

    上述方法tableView会调用数据源中的

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
    

    在数据源方法中,tableView会创建所有的UITableViewCell.一般编码思路是:每当有人提问就调用[tableView reload]方法,并让其滚动到底部.但是会出现错误:

    *** Terminating app due to uncaught exception 'NSRangeException', reason: '-[UITableView _contentOffsetForScrollingToRowAtIndexPath:atScrollPosition:]: row (14) beyond bounds (14) for section (0).'
    

    究其原因,是tableView在创建cell的数据源方法还未完成时,已经在调用numberOfRows的数据源方法了.
    假如第一次reloadData时,需要创建10个Cell;
    当在创建第10个cell时,又走了reloadData方法,要求创建8个Cell;
    上述情况出现时,就会上面的错误.
    根据错误原因,可以通过设置UITableView的contentSize属性来解决. 下面是我模仿上述情景写的一个Demo:

    - (void)viewDidLoad {
        [super viewDidLoad];
        self.arrM = [NSMutableArray arrayWithObjects:@"1",@"2", nil];
        self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self action:@selector(itemClick)];
    }
    
    - (void)itemClick{
        for (int i = 0; i < 100; i++) {
            NSLog(@"%.0f", self.tableView.contentSize.height);
            NSLog(@"%@", NSStringFromCGPoint(self.tableView.contentOffset));
            dispatch_async(dispatch_queue_create("a", DISPATCH_QUEUE_CONCURRENT), ^{
                NSLog(@"%@",[NSThread currentThread]);
                [self.arrM addObject:@"1"];
                if (self.arrM.count > 30) {
                    [self.arrM removeObjectsInRange:NSMakeRange(0, 29)];
                }
                dispatch_async(dispatch_get_main_queue(), ^{
                    [self.tableView reloadData];
                    NSLog(@"%.0f", self.tableView.contentSize.height);
                    CGPoint offset = CGPointMake(0,self.tableView.contentSize.height - self.tableView.frame.size.height);
                    if (offset.y < 0) {
                        offset = CGPointMake(0, -44);
                    }
                    [self.tableView setContentOffset:offset animated:NO];
                });
            });
        }
    }
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
        return self.arrM.count;
    }
    - (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
        if (!cell) {
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"];
        }
        cell.textLabel.text = [NSString stringWithFormat:@"%zd组%zd行",indexPath.section,indexPath.row];
        return cell;
    }
    - (BOOL)prefersStatusBarHidden{
        return YES;
    }
    

    源码地址:

    https://github.com/zhudong10/ZDZhiBoTableView.git
    

    相关文章

      网友评论

      • 0fad9d020547:这样写有很大的隐患,self.arrM 在主线程里面被访问,在后台线程中被修改,但没有任何同步措施。上线如果出了问题,很难排查出原因。
        0fad9d020547:@uniapp 把对self.arrM的修改dispatch 到主线程, 或者在 后台线程创建一个新的数组,然后切换到主线程直接替换。
        uniapp:有什么好的解决思路吗?
      • 游龙飞雪:不明白为什么要-44,博主能解释下吗谢谢!
        游龙飞雪:@uniapp 哦。
        uniapp:UINavigationBar高度
      • 61169488d83b:如果把刷新 dispatch_async(dispatch_get_main_queue(),改为同步的呢dispatch_sync(dispatch_get_main_queue() ?这样可以解决吗?
        微光星芒:@uniapp 我是这样处理的, 没问题.
        uniapp:@微光星芒 你可以试试
        微光星芒:你是说反了吗? dispatch_async(dispatch_get_main_queue() 用这个方法可以解决问题. 等待主线程的代理方法执行完,再进行位置滚动
      • 羊肉泡馍啊:其实用这个就可以解决了
        [self.messageTableView reloadData]
        CGPoint offset = CGPointMake(0,self.messageTableView.contentSize.height - self.messageTableView.frame.size.height);
        [self.messageTableView setContentOffset:offset animated:NO];
        游龙飞雪:请问如 offset.y < 0 怎么办?
        晓风_d9ef:谢谢大神,我试试
        uniapp:这个方法更好, 多谢指正.
      • key3board:恩。 可以。 不错

      本文标题:UITableView滚动到底部时崩溃的解决方法

      本文链接:https://www.haomeiwen.com/subject/ygcosttx.html