【问题标题】:What's the relationship between UI animation and the main runloopUI动画和主runloop有什么关系
【发布时间】:2014-04-16 17:40:13
【问题描述】:

我有这个代码来等待加载任务,显示一个 activityIndi​​cator 视图

  if (isLoading) {
    self.tipView = [[BBTipsView alloc] initWithMessage:@"loading..." showLoading:YES parentView:self.view autoClose:NO];
    self.tipView.needsMask = YES;
    [self.tipView show];
    while (isLoading) {
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
    }
    [self.tipView close];
}

加载视图将进行动画处理,直到 isLoading 变为 false。这是我的问题: 在主线程中运行 runloop 将阻塞主线程,直到有源事件到来或计时器触发。但是为什么加载视图在主运行循环没有返回时保持动画?

-----由 bupo 编辑----

我发现当计时器触发时,runloop 不会返回。这说明 CADisplayLink 计时器触发的动画刷新 ui 是有意义的。

Note that from the perspective of NSRunloop, NSTimer objects are not "input"—they are a special type, and one of the things that means is that they do not cause the run loop to return when they fire.

【问题讨论】:

  • 现代动画与 RunLoop 关系不大。它们依赖称为 Display Links 的计时器原语,可以在后台线程上运行,以确保与显示器而不是 CPU 相关联的良好刷新率。
  • 你的意思是UI刷新不在主线程上运行?
  • 你得到的显示回调只是主线程。计时器是在后台运行的。

标签: objective-c multithreading cocoa animation


【解决方案1】:

NSRunLoop 方法runMode:beforeDate: 一直运行到给定日期或直到找到要处理的单个事件 - 之后调用返回。您在主运行循环 ([NSRunLook currentRunLoop]) 上调用它。因此,即使您认为您正在阻塞主运行循环,但您并没有——您正在导致事件得到服务。因此,即使您可能认为自己“阻塞”了主运行循环,动画计时器也可以运行。

要确认这一点,请注释掉对 runMode:beforeDate: 的调用,您应该会看到 UI 冻结,直到操作完成。

编辑:请参阅 CodaFi 对您的问题的评论。如果您出于兴趣而将对 runMode:beforeDate: 的调用注释掉,实际会发生什么?

原答案:

不建议将这种代码风格用于启动和停止 UI 动画。 除非必须,否则不要乱用运行循环。而且有一个紧密的循环来检查布尔标志是否从其他地方发生了变化,这通常是一种代码味道,这意味着有更好的方法。

相反,它是异步执行的,而不是坐在主线程上:

   // on main thread
   self.tipView = [[BBTipsView alloc] initWithMessage:@"loading..." showLoading:YES parentView:self.view autoClose:NO];
   self.tipView.needsMask = YES;
   [self.tipView show];
} // end of the method

- (void)loadingHasFinished {
    // assuming this method called on main thread
    [self.tipView close];
}

显然,您必须确保适当地调用 loadingHasFinished

如果loadingHasFinished 是在后台线程而不是主线程上调用的,你会想要这样的:

- (void)loadingHasFinished {
    dispatch_async(dispatch_get_main_queue(), ^{
        [self.tipView close];
    }); 
};

【讨论】:

  • 是的,我知道有更好的方法。但在这种情况下,我只想知道 ui 动画是否通过主 runloop 刷新 ui?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-02-11
  • 1970-01-01
  • 1970-01-01
  • 2015-03-17
  • 1970-01-01
  • 1970-01-01
  • 2015-03-29
相关资源
最近更新 更多