繁体   English   中英

进行很多需要在主线程上执行的操作时,避免阻塞UI

[英]Avoid blocking UI when doing a lot of operations that are required to be on main thread

我需要做一系列可能很长的调用,这些调用必须在主线程上发生(因为否则UIKit会失败)。 “长”是指在iPad 3上进行10,000次操作,每个操作持续0.1秒。

显然,一次遍历所有这些可能不是最好的主意。

我不知道如何在主线程上执行所有这些操作同时又留有足够的呼吸空间来保持UIKit的响应能力和看门狗的睡眠状态(即,不会因为占用运行循环而被终止)。

有人有主意吗? 我将针对iOS 5。

具体来说,我想做的是缓存UITextPosition ,因为UITextView在获取UITextPosition显然采用了非缓存的迭代方法,这意味着在执行positionFromPosition:textview.beginningOfDocument offset:600011非常慢。但是获取positionFromPosition:aPositionAt600000 offset:11速度要快得多。 实际上,在我的测试案例中,前者花费了100秒(在主线程上!) ,而后者实际上是瞬时的。

为什么要在主线程上执行此操作? 典型的答案是在后台线程上执行这些操作,并将UI更新发送回主线程。 例如,您可以使用Grand Central Dispatch

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // do my time consuming task and everytime it wants to update the UI, 
    // it should dispatch that back to the main queue, e.g.

    for (NSInteger i = 0; i < 10000; i++)
    {
        // do my background work

        // now update the UI
        dispatch_async(dispatch_get_main_queue(), ^{
            // update the UI accordingly
        });
    }
});

更新:

听起来您必须在前台执行此操作,因此也许使用NSTimer可能更好。 我不是NSTimer的大人物,但它可能看起来像以下内容。

首先,确保您有一个类实例变量:

NSTimer *_timer;

接下来,可以使用以下命令对其进行初始化:

- (void)startTimer
{
    _timer = [NSTimer timerWithTimeInterval:0.0 target:self selector:@selector(timerCallback:) userInfo:nil repeats:YES];
    NSRunLoop *runloop = [NSRunLoop currentRunLoop];
    [runloop addTimer:_timer forMode:NSDefaultRunLoopMode];
}

然后,这将调用timerCallback,也许在每次调用时都处理一个UITextPosition:

- (void)timerCallback:(NSTimer*)theTimer
{
    BOOL moreTextPositionsToCalculate = ...;

    if (moreTextPositionsToCalculate)
    {
         // calculate the next UITextPosition
    }
    else
    {
         [self stopTimer];
    }
}

完成后,您可以像这样停止计时器:

- (void)stopTimer
{
    [_timer invalidate];    
    _timer = nil;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM