我正在构建我自己的活动指示器,就像在重度操作之前应该淡入的类,并在操作完成时淡出。这工作正常,直到我遇到以下情况:
[[MyLoaderClass sharedInstance] displayLoaderInView:self.view];
for( int i = 0; i < 1000; i++ ) {
NSLog(@"Performing heavy operation...");
}
[[MyLoaderClass sharedInstance] removeLoaderInView:self.view];
第一行发生的事情是我的加载器视图被分配,子视图并告知淡入标准的UIView动画。但是,动画无法启动(如setAnimationWillStartSelector:
所示),直到 重度操作完成后才会显示。
现在,主要线程上的大量操作当然是要避免的,但我仍然希望我的loader类能够工作,无论程序员可能会抛出它。
我尝试将加载程序移动到一个单独的线程中,并从那里开始动画效果很好,但导致崩溃,因为从主线程以外的线程操作视图并不酷。
我的问题:有可能做我想做的事,和/或我应该为此烦恼吗?
答案 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];
NSOperationQueue很棒,但不完全直观。