动画在进入后台后崩溃App

时间:2013-05-19 12:20:48

标签: iphone ios animation memory crash

在完成关于如何清理动画的反馈后,我实施了以下内容;

- (void)onAnimationComplete:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
    UIImageView *AnimationImageEnd = context;
    [AnimationImageEnd removeFromSuperview];
    [AnimationImageEnd release];
}

并将它们设置为关闭(我删除了一些帧和旋转计算);

UIImageView * AnimationImageStart = [[UIImageView alloc] initWithImage: AnimationImage];
[self addSubview:AnimationImageStart];
[UIView beginAnimations:nil context:AnimationImageStart];
[UIView setAnimationDuration:iSpeed];
AnimationImageStart.transform = transform;
[UIView setAnimationDidStopSelector:@selector(onAnimationComplete:finished:context:)];
[UIView setAnimationDelegate:self];
[UIView commitAnimations];

这似乎工作正常,并在动画完成后清理所有已用内存。

自从实施这种方法以来,如果动画已经预先启动,我现在遇到了重新打开应用程序的问题。该应用程序现在崩溃,出现以下错误;

*** -[UIImage _isDecompressing]: message sent to deallocated instance 0x21083ad0

我有一个修补程序,它似乎完全取决于使用的版本。如果我删除[AnimationImageEnd release];崩溃停止(但它显然会启动一些内存泄漏..)。

是否有一些简单的事情我误解了动画和应用程序从后台进入/重新开放?

我的猜测是iOS会在进入后台后自动清理正在进行的任何动画,并自动将释放发送到每个动画。如果是这种情况,我应该只是简单地期望它们已被清理并在applicationDidBecomeActive中保留一个标志以绕过该版本吗?


修改1 我已经读过onAnimationComplete上的完成标志会让我知道动画是否完成了它的完整动画。是否足以相信如果它没有完成它已经被清理(从superview中删除并被释放)?


修改2

根据David的回复,我已将此更新为一个块;

[UIView animateWithDuration:5.0f
                          delay:0.0f
                        options:0
                     animations:^{

                         imgStart.frame = CGRectMake( 0,  0, 10.0f, 10.0f);

                     }
                 completion:^(BOOL finished){

                     [imgStart removeFromSuperview];

                     //This still crashes the App as soon as the App returns from being in the background
                     [imgStart release];

                 }];

仍然存在与上面详述的相同的行为。根据编辑1,是否足以假设每当完成的BOOL为NO时,它已经被清理(从superview +中删除)?


非常感谢任何信息。

拉​​尔夫

1 个答案:

答案 0 :(得分:0)

首先,请不要使用对象的首字母大写字母 - 为类保留它们(这使得我们大多数人阅读代码变得更加困难)。

通常,在回调中释放对象是不好的做法。使用主队列的调度块来释放对象或performSelectorOnMainthread:,看看是否有帮助。

编辑:并不意味着暗示你需要完整的阻止。如果动画没有完成,再次阅读文档并不表示保留更改。由于您的代码中有一个版本,因此您没有使用ARC。

非ARC:所以imgStart是alloc / inited,没有自动释放,所以它的保留计数是1.你将它添加到子视图,它现在是两个。您(或系统)将其从子视图中删除,现在为1.最终版本使其为0(我忽略了块本身的保留/释放)。我只是无法看到系统如何释放它,因为它不是它可以看到的任何地方(它不是一个ivar,所以viewDidUnload无法释放它)。现在这是一个谜。

假设你转换为ARC:imgStart在动画开始时被释放,两个东西保留它,子视图数组和块。当它从子视图数组中删除时(由who who),保留计数减少1,当块完成时它也将释放它,导致保留计数变为0,因此它将被释放。

如果上面没有任何铃声或帮助,你至少可以尝试找到该对象被取消分配的时间/地点。在.m文件中创建一个UIImageView子类:

@implementation MyIV : UIIMageView
@end
@interface MyIV

- (void)dealloc
{
  [super dealloc];
  NSLog(@"MYIV DEALLOC!!!!");    
}
@end

在日志消息上放置一个断点,您可以确切地看到它被取消分配的确切位置。我发现这在过去非常有帮助我创建了一个ARC类,即使对于github上的类集群,也称为Tracker