在不阻塞主线程的情况下更新 tableView

Posted

技术标签:

【中文标题】在不阻塞主线程的情况下更新 tableView【英文标题】:updating tableView without blocking main thread 【发布时间】:2012-07-17 14:16:19 【问题描述】:

所以我有一个带有 UIScrollView 的 iPad 应用程序。滚动视图一次显示大约 5-10 个 UIView,在这些 UIView 内部是一个 tableView。所以基本上一次显示了 5-10 个 UITableView。问题是,当我滚动 UIScrollView 时,它会在 UITableView 上调用 reloadData,在这种情况下,它将设置 UITableView 单元格的文本。方法如下:

if (shouldUpdateComment)
        shouldUpdateComment = NO;
        __block __weak AHCommentsTableViewCell * weakSelf = self;
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^

            NSString *commentsText = [NSString stringWithFormat:@"%@ %@", self.imageComment_.username_, self.imageComment_.text_];
            NSMutableAttributedString* attrStr = [[[NSMutableAttributedString alloc] initWithString:commentsText] autorelease];

            NSRange usernameRange = [commentsText rangeOfString:self.imageComment_.username_];
            if (usernameRange.location != NSNotFound)
                [attrStr setTextColor:[UIColor colorWithRed:86.0/255.0 green:134.0/255.0 blue:172.0/255.0 alpha:1.0] range:usernameRange];

            

            NSString * url = [NSString stringWithFormat:@"userid://%@", self.imageComment_.id_];
            usernameRange = [commentsText rangeOfString:self.imageComment_.username_];
            if (usernameRange.location != NSNotFound)
                [weakSelf.commentsText_ addLink:[NSURL URLWithString:url] range:usernameRange];
            

            NSRange range;
            range.location = 0;
            range.length = commentsText.length;

            [attrStr setFont:[UIFont fontWithName:@"HelveticaNeue" size:14] range:range];

            dispatch_async(dispatch_get_main_queue(), ^
                [weakSelf.commentsText_ setAlpha:0.0];
                [weakSelf.commentsPostedTime_ setAlpha:0.0];
                [weakSelf.commentsText_ setFrameWidth:self.contentView.frameWidth - self.profilePicture_.frameWidth - kCommentsPadding];
                [weakSelf.commentsText_ setFrameHeight:weakSelf.imageComment_.commentHeight_ - 30];
                [weakSelf.commentsText_ setAttributedString:attrStr];

                dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^
                    [weakSelf parseTagsInComment:commentsText];
                );

                NSString *timePosted = [NSString timestampToString:weakSelf.imageComment_.createdTime_];
                CGSize commentsTimeSize = [timePosted sizeWithFont:weakSelf.commentsPostedTime_.font constrainedToSize:CGSizeMake(weakSelf.commentsText_.frameWidth, 50)];
                [weakSelf.commentsPostedTime_ setText:timePosted];
                [weakSelf.commentsPostedTime_ setFrameWidth:commentsTimeSize.width];
                [weakSelf.commentsPostedTime_ setFrameHeight:commentsTimeSize.height];
                [weakSelf.commentsPostedTime_ setFrameY:weakSelf.commentsText_.frameY + weakSelf.commentsText_.frameHeight];
                [weakSelf.commentsPostedTime_ setFrameX:weakSelf.commentsText_.frameX];

                [UIView animateWithDuration:0.3 animations:^
                    [weakSelf.commentsText_ setAlpha:1.0];
                    [weakSelf.commentsPostedTime_ setAlpha:1.0];
                ];
            );

        );

    

现在上面的方法很重,因为我试图在仪器上对其进行分析。当它在滚动视图滚动时执行时,它会滞后非常糟糕。所以我所做的就是等到滚动视图停止滚动并调用上面的方法,问题是它会导致非常糟糕的用户体验。有什么想法吗?

【问题讨论】:

为什么一定要调用reloadData? 因为数据源改变了? 我以为您在滚动时会重新加载...数据源多久更改一次? 所以基本上在显示新的 UIView 时.. 我正在调用 setTableViewData: 如果您尝试在移动的滚动视图(即表格)中为视图设置动画,您将获得可怕的性能。 ios 在设计时并未考虑到这一点。如果 scrollView 处于运动状态,只需编写图像 - 仅在停止时对其进行动画处理。 【参考方案1】:

UI的改变只能在主线程中进行,也就是说,如果你想改变文本,改变UIControl的框架等,必须在主线程中实现。

这就是 UIKit 框架所支持的

【讨论】:

以上是关于在不阻塞主线程的情况下更新 tableView的主要内容,如果未能解决你的问题,请参考以下文章

如何在不阻塞主线程的情况下使用 join() 创建多个 C++ 线程?

如何在不使用 C++/C 中的阻塞函数的情况下将值从线程返回到主函数

子线程怎么不阻塞主线程

如何在不破坏 UI 的情况下将搜索放在另一个线程中?

如何在不放弃主线程的情况下为 Python 使用 CoreBluetooth

等待一段时间不阻塞主线程