UIView动画被繁忙的主线程阻止

时间:2011-03-10 20:31:52

标签: iphone objective-c animation uiview

我正在构建我自己的活动指示器,就像在重度操作之前应该淡入的类,并在操作完成时淡出。这工作正常,直到我遇到以下情况:

[[MyLoaderClass sharedInstance] displayLoaderInView:self.view];

for( int i = 0; i < 1000; i++ ) {
   NSLog(@"Performing heavy operation...");
}

[[MyLoaderClass sharedInstance] removeLoaderInView:self.view];

第一行发生的事情是我的加载器视图被分配,子视图并告知淡入标准的UIView动画。但是,动画无法启动(如setAnimationWillStartSelector:所示),直到 重度操作完成后才会显示。

现在,主要线程上的大量操作当然是要避免的,但我仍然希望我的loader类能够工作,无论程序员可能会抛出它。

我尝试将加载程序移动到一个单独的线程中,并从那里开始动画效果很好,但导致崩溃,因为从主线程以外的线程操作视图并不酷。

我的问题:有可能做我想做的事,和/或我应该为此烦恼吗?

2 个答案:

答案 0 :(得分:2)

作为约书亚史密斯的建议的替代方案,如果在不同的线程上混淆了你的操作,只要确保你在启动UIView动画和开始繁重的代码之间退出runloop。 E.g。

    ...
    [[MyLoaderClass sharedInstance] displayLoaderInView:self.view];
    [self performSelector:@selector(performHeavyOperation) withObject:nil afterDelay:0];
}

- (void)performHeavyOperation
{
   for( int i = 0; i < 1000; i++ ) {
      NSLog(@"Performing heavy operation...");
   }

   [[MyLoaderClass sharedInstance] removeLoaderInView:self.view];
}

performSelector:withObject:afterDelay:导致将来在runloop上调度nomated选择器。将延迟设置为0意味着它会尽快添加到runloop中。

由于各种原因,只有当你允许调用堆栈一直展开到调用堆栈时,相当多的UIView东西才会生效。就这样,例如,如果你这样做:

view.frame = aNewFrame;
view.someOtherPropertyThatWouldCauseAVisibleChange = anotherValue;

然后UIView最终只会重绘一次,而不是两次。

答案 1 :(得分:1)

将您的繁重操作放在NSOperationQueue中,然后它不会阻止主线程。

@interface MyClass : NSOperation {

}

@end


@implementation MyClass

-(void) main {

    for( int i = 0; i < 1000; i++ ) {
        NSLog(@"Performing heavy operation...");
    }    

}

@end

然后,在上面的代码中:

[[MyLoaderClass sharedInstance] displayLoaderInView:self.view];
NSOperationQueue *q = [[NSOperationQueue alloc] init];
MyClass *c = [[[MyClass alloc] init] autorelease];
[q addOperation:c];
[q waitUntilAllOperationsAreFinished];

[[MyLoaderClass sharedInstance] removeLoaderInView:self.view];

阅读文档,您也需要它们:http://developer.apple.com/library/mac/#documentation/cocoa/reference/NSOperationQueue_class/Reference/Reference.html

NSOperationQueue很棒,但不完全直观。