UI动画和主runloop之间的关系是什么

时间:2014-04-11 12:51:00

标签: objective-c multithreading cocoa animation

我有这段代码等待加载任务,显示一个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将阻塞主线程,直到有源事件或计时器触发。但为什么加载视图在主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.

1 个答案:

答案 0 :(得分:0)

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

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

编辑:请参阅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];
    }); 
};