【问题标题】:NSTimer/NSOperationQueue performing inconsistently iphoneNSTimer/NSOperationQueue 执行不一致 iphone
【发布时间】:2011-06-30 01:41:56
【问题描述】:

我正在尝试解决围绕 NSTimer/NSOperationQueue 执行不一致的 UI 问题。我看到无论我使用 NSTimer 还是 NSInvocationOperation 来触发下面的代码,很多时候性能是需要的,但有几次行为很慢(如下例所示,代码有时会运行超过 1 秒)。

这是我通过 NSInvocationOperation 调用的代码:

-(void) progressAsynch{
    for (count = 1; count<=100; count++) {

        // Reposition Label's CGRect.
        [self performSelectorOnMainThread:@selector(moveLabelToNewPosition) withObject:nil waitUntilDone:YES];

        //Update the progress of the progress view
        [self performSelectorOnMainThread:@selector(advanceProgressViewProgress) withObject:nil waitUntilDone:YES];

        //Sleep for 10 millisecs
        [NSThread sleepForTimeInterval:0.01];

        //if the progress view has progressed fully call main thread to to next tasks.
        if(progressView.progress == 1) {
            [self performSelectorOnMainThread:@selector(processResult) withObject:nil waitUntilDone:YES];
        }
    }

}

NSTimer(每10毫秒触发一次)调用的方法的代码和上面的很相似,只是里面没有for循环。

显然,似乎在这个处理之外有一些东西经常降低这个性能。

很想知道您是否遇到过类似的问题,或者您是否有任何可以帮助我的建议/花絮。

提前谢谢..

【问题讨论】:

  • 看起来你正在做一些简单的动画。您是否有任何理由不使用内置的 UIViews。动画功能?此外,正如文档所述,NSTimer 不能保证准确性,并且取决于处理器负载。你不能指望它有任何真正的准确性。
  • 感谢您的评论。不使用内置动画功能,因为我也在为循环中的每次迭代更新标签文本。

标签: iphone nstimer nsoperationqueue


【解决方案1】:

线程间通信并没有那么快,waitUntilDone:YES 增加了额外的线程同步开销并且完全没有必要(我很确定 performSelector 是序列化的)。你可能会有更好的运气来做类似的事情

-(void) progressAsynch{
    for (count = 1; count<=100; count++) {
        [self performSelectorOnMainThread:@selector(stuff) withObject:nil waitUntilDone:NO];
        [NSThread sleepForTimeInterval:0.01];
    }
}

但是,还是很糟糕。看起来self 是一个视图或视图控制器,它将由 NSInvocation 保留,并可能在后台线程上释放。大多数 UIKit 都不是线程安全的; Game Center 示例代码很大 声明 UIKit 类甚至不应该在后台线程上释放,因为释放可能会导致 -dealloc,这在 UIKit 类中可能不是线程安全的. (哎哟)

(另请注意,您对progressView.progress 的调用对于后台线程来说是不安全的。)

您也处于可能的极限:我很确定 iOS 时间片是 10 毫秒,这意味着如果有任何其他事情需要 CPU (并且有很多后台进程;请尝试使用Instruments 中的 Activity Monitor 有时)您的动画可能会出现滞后。

最后,通过一些音频播放代码,我们注意到 NSTimer 不是很准确。我不确定为什么。我认为我们使用 SIGALRM 修复了它(以及可能不是信号安全的代码,叹气)。

使用 CADisplayLink 可能会更好,它与显示器的刷新率同步(我认为你通过它[UIScreen mainScreen])并设计用于动画,所以它应该表现更好一些。 iOS 3.1+,但我怀疑支持 3.0 没什么意义。

【讨论】:

  • 感谢您的见解和建议。事实上,我似乎试图在 10 毫秒时将 IOS 推得太多了。我尝试通过 CADisplayLink 触发该方法,但之前仍然得到类似的响应行为。因此,我将循环调整为基于“setInterval:1”,并且获得了可以管理的性能水平。感谢 CADisplayLing 的建议——继续使用它。
  • 所以,事实证明,我又回到了这个问题的反面。我的代码并没有真正改变,但是 NStimer 完全按照需要工作,并且 CADisplayLink 执行得太快了。所以想知道 setInterval 是否是绝对值。想知道如何控制代码的行为以准确响应我想要的时间间隔。
  • 另外,不确定这是否影响到我,如果影响到我会很沮丧:idevgames.com/forums/thread-8006.html
  • 设置间隔?你的意思是frameInterval?我很确定这取决于屏幕刷新率,我很确定是 60 Hz。
  • 是的,我就是这个意思。顺便说一句,我在完成循环处理后解决了这个问题。 : [displayLink removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-01-22
  • 2023-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多