3

我需要在主线程上执行一系列可能很长的调用(因为否则 UIKit 会退缩)。“长”是指在 iPad 3 上进行 10,000 次操作,每次操作持续 0.1 秒。

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

我不知道如何在主线程上执行所有这些,同时留出足够的喘息空间来保持 UIKit 响应和看门狗睡着(即不会因为占用运行循环而终止)。

有人有想法吗?我将瞄准iOS 5。

具体来说,我正在尝试做的是缓存UITextPositions,因为 aUITextView显然在获取 s 时采用了非缓存的迭代方法UITextPosition,这意味着它在执行时非常非常慢positionFromPosition:textview.beginningOfDocument offset:600011,但在获取时要快得多positionFromPosition:aPositionAt600000 offset:11。事实上,在我的测试用例中,前者需要 100 多秒(在主线程上!),而后者几乎是瞬时的。

4

1 回答 1

6

为什么要在主线程上做呢?典型的答案是在后台线程上执行这些操作,并将 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
        });
    }
});

更新:

听起来您必须在前台执行此操作,因此使用 aNSTimer可能会更好。我不是一个大个子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;
}
于 2012-06-27T18:45:52.053 回答