我们将大约30个完整的320 x 480图像加载到动画阵列中。这些图像尺寸非常小,每张图像约5-7Kb。问题是当我们运行循环来为图像填充数组时,它似乎会在填充此数组时暂停整个应用程序。是否有一种方法可以将这个可变数组与图像一起加载到一个单独的线程中,以便在不损害性能的情况下填充数组?感谢
NSMutableArray *totalAnimationImages = [[NSMutableArray alloc] initWithCapacity:numOfImages];
for(int i = 1; i < numOfImages; i++) {
[totalAnimationImages addObject:[UIImage imageNamed:
[NSString stringWithFormat:@"%@%d.png", image, i]]];
}
annImage.animationImages = totalAnimationImages;
annImage.animationDuration = speed; //.4 second
annImage.animationRepeatCount = 1; //infinite loop
[annImage startAnimating]; //start the animation
[totalAnimationImages release];
在处理这个问题时,并使用shabzco提供的线程建议,我提出了以下代码来处理循环,在图像视图中更改图像,看起来绝对没有性能损失。这只能在NSMutableArray中一次保存一个图像而不是30个。正如Richard J. Ross III所说,一旦动画开始,它将把所有图像处理成“内存中的位图格式”。这是漫长的等待/延迟来自的地方。在下面的代码中,每次图像更新只发生一次,而不是仅仅为了启动动画。我在建议的调度线程中使用带有计时器的while循环,以防止此计时器影响主线程,从而可能在动画期间产生不稳定的性能。请提供有关此解决方案的反馈!感谢
更新:Shabzco建议我用“imageWithContentsOfFile”替换“ImageNamed”,以避免因ImageNamed可能在内存中缓存图像而导致奇怪的内存泄漏。这是在运行xcode探测器并观看“Real Memory”计数器后发现的。很明显,每次动画运行时,真正的内存会越来越多,直到最终应用程序崩溃。用“imageWithContentsOfFile”替换“ImageNamed”后,问题就消失了。我已经更新了以下代码。
annImage.image = [UIImage imageNamed:@""];
[annImage setAlpha:1.0];
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(concurrentQueue, ^{
NSTimeInterval timeout = 1.00 / speed; // Number of seconds before giving up
NSTimeInterval idle = 1.00 / 8; // Number of seconds to pause within loop
BOOL timedOut = NO;
NSDate *timeoutDate;
for(int i = 1; i < numOfImages; i++) {
timeoutDate = [[NSDate alloc] initWithTimeIntervalSinceNow:timeout];
timedOut = NO;
while (!timedOut)
{
NSDate *tick = [[NSDate alloc] initWithTimeIntervalSinceNow:idle];
[[NSRunLoop currentRunLoop] runUntilDate:tick];
timedOut = ([tick compare:timeoutDate] == NSOrderedDescending);
[tick release];
}
dispatch_async(dispatch_get_main_queue(), ^{
//annImage.image = [UIImage imageNamed:
// [NSString stringWithFormat:@"%@%d.png", image, i]];
NSString *filePath = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"%@%d", image, i] ofType:@"png"];
annImage.image = [UIImage imageWithContentsOfFile:filePath];
});
}
dispatch_async(dispatch_get_main_queue(), ^{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration: 0.3];
[annImage setAlpha:0.0];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
[UIView commitAnimations];
});
});
答案 0 :(得分:1)
这将使你的for循环发生在另一个线程中,并且一旦所有内容都被加载就会开始动画。
@autoreleasepool {
NSMutableArray *totalAnimationImages = [[NSMutableArray alloc] initWithCapacity:numOfImages];
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(concurrentQueue, ^{
for(int i = 1; i < numOfImages; i++) {
[totalAnimationImages addObject:[UIImage imageNamed:
[NSString stringWithFormat:@"%@%d.png", image, i]]];
}
annImage.animationImages = totalAnimationImages;
annImage.animationDuration = speed; //.4 second
annImage.animationRepeatCount = 1; //infinite loop
[annImage startAnimating]; //start the animation
dispatch_async(dispatch_get_main_queue(), ^{
[totalAnimationImages release];
});
});
}