我正在开发一个带有UITableView的iOS应用程序,它在某个阶段添加或删除了一堆行。由于存在大量行,因此此操作可能需要很长时间。但是,我不能轻易确定是否需要很长时间。
我想显示一个UIActivityIndicator(微调器),只有这个操作需要很长时间。我一直这样做的方法是开始冗长的操作,经过一段时间(比如0.5秒)我们测试操作是否仍在运行,如果是,我们就开始显示UIActivityIndicator。
如果你可以在后台线程中运行冗长的操作,这没问题。但是,这种特殊情况很棘手,因为漫长的操作(deleteRowsAtIndexPaths:withRowAnimation :)必须在主线程中运行(如果我在后台线程中运行此方法,则当后台线程尝试更新UI时,应用程序偶尔会崩溃)。 / p>
我尝试过的最新事情就是:
- (void) manipulateTableView
{
stillBusy = YES;
[self performSelectorInBackground:@selector(waitBeforeShowingBusyIndicatorForView:) withObject:view];
.
.
.
[self performSelectorOnMainThread:@selector(deleteRowsAtIndexPathsWithRowAnimation:) withObject:args waitUntilDone:YES];
stillBusy = NO;
}
- (void) waitBeforeShowingBusyIndicatorForView:(UIView*) view
{
usleep((int) (BUSY_INDICATOR_DELAY * 1000000));
if (stillBusy)
[self performSelectorOnMainThread:@selector(showBusyIndicatorForView:) withObject:view waitUntilDone:NO];
}
因为showBusyIndicatorForView:操纵UI,所以必须在主线程上调用它,否则应用程序可能会崩溃。
当deleteRowsAtIndexPaths:withRowAnimation:花费很长时间时,waitBeforeShowingBusyIndicatorForView中的延迟:expires并调用performSelectorOnMainThread:...方法并立即返回。但是,然后showBusyIndicatorForView:方法仅在调用deleteRowsAtIndexPaths之后调用:withRowAnimation:完成,这会破坏目的。
我想我明白为什么会这样。 deleteRowsAtIndexPaths:withRowAnimation:方法在主循环的迭代中运行,并且在运行时,对showBusyIndicatorForView:的调用将作为主循环的消息排队。只有在主循环完成执行deleteRowsAtIndexPaths:withRowsAnimation之后:它轮询队列以获取下一条消息,然后开始执行showBusyIndicatorForView:。
有没有办法让这个东西正常工作。是否有可能中断主循环并使其立即执行showBusyIndicatorForView?
答案 0 :(得分:3)
我有两个选择:
修改长时间运行的前台例程,使其分成多个块,您可以将这个过程的每个步骤重复分配到主队列。并且以这样的方式进行设计,使得它调度慢前台任务的每个部分,并且仅在前一部分完成时将下一步调度到主队列。 (不要只为主队列排队大量的进程。)这样,你就可以让微调器在排队时与其他工作相吻合。如果您正在为删除设置动画,这可能是不可能的,但是再次,我无法想象单一deleteRowsAtIndexPaths
需要花费很长时间。
可能更好,如果更新花了这么长时间,我会问为什么会这样。 deleteRowsAtIndexPaths
不应该考虑到这一点。具体来说,不要发出多个deleteRowsAtIndexPaths
,而是构建要删除的行的NSMutableArray
,然后在单个UI调用中删除它们。我刚刚删除了998行(包括它们的基础模型对象),它几乎是瞬间的。
如果可能,我会倾向于选项2.
答案 1 :(得分:0)
在主线程上运行冗长的操作时,无法更新UI。
如果你的延迟确实是由-deleteRowsAtIndexPaths:withRowAnimation:
引起的(如果你要求表格视图动画删除几千行,那么很可能是最好的解决方案是避免动画超出某个(相对较小的)阈值,只需拨打-reloadData
。
答案 2 :(得分:0)
首先,为了记录,我只为所有行调用了一次deleteRowsAtIndexPaths(数千个:O!)。
我做的关键观察是,动画开始时屏幕上只能看到少量行。特别是该部分的顶行,因为通过点击该部分的标题触发了行的删除。因此,行不一定都是动画的一部分。我可以先删除所有不可见的行(没有动画),然后只用动画删除可见的行。
然后我对deleteRowsAtIndexPaths进行了两次调用 - 第一次删除了所有不可见的行,第二次删除了可见(顶部)行。现在第一次调用deleteRowsAtIndexPaths花了很长时间,因为它必须删除数千行,并且活动指示器视图再次无法开始动画。然后我将行删除的第一阶段更改为一个循环,一次删除行200,如下所示:
for ( /* next range of invisible rows */ )
{
// Compute index paths of the bottom 200 rows.
[self performSelectorOnMainThread:@selector(deleteRowsAtIndexPathsWithRowAnimation:) withObject:args waitUntilDone:YES];
}
启动活动指示器动画的方法将在对deleteRowsAtIndexPaths ...的两次后续调用之间排队:。
有趣的是:现在我一次要删除200行,这需要相当长的时间,但它仍然比我一次删除它们的速度快得多! :|