0

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

- (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 版本];崩溃停止(但它显然开始了一些内存泄漏......)。

我对动画和应用程序从后台进入/重新打开有什么简单的误解吗?

我的猜测是,iOS 会在进入后台后自动清理正在进行的任何动画,并自动触发每个动画的发布。如果是这种情况,我是否应该只是期望它们已被清理并在 applicationDidBecomeActive 中持有一个标志以绕过发布?


编辑 1 我已经读到 onAnimationComplete 上的完成标志会让我知道动画是否完成它是完整的动画。仅仅相信如果它没有完成它已经被清理(从超级视图中删除并发布)就足够了吗?


编辑 2

根据下面大卫的回复,我已将其更新为一个块;

[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 中删除 + 发布)就足够了吗?


非常感谢任何信息。

拉尔夫

4

1 回答 1

0

First, please don't use an initial capital letter for an object - reserve those for classes (it makes reading code much harder for most of us).

Generally it's bad practice to release objects in callbacks. Use a dispatch block to the main queue to release the object or a performSelectorOnMainthread:, and see if that helps.

EDIT: didn't mean to imply you needed a complete block. Reading the docs again shows no indication of retain change if the animation does not complete. Since you have a release in your code, you are not using ARC.

Non-ARC: so imgStart is alloc/inited, no autorelease, so its retain count is 1. You add it to the subview, its now two. You (or the system) removes it from the subview, its now 1. The final release makes it 0 (I'm ignoring the retain/release by the block itself). I just cannot see how the system could release it, as its not really anywhere it can be seen (its not an ivar, so viewDidUnload cannot release it). Right now this is a mystery.

Suppose you converted to ARC: imgStart is released at the start of the animation, two things retain it, the subview array and the block. When its removed from the subview array (by whoever), retain count goes down by 1, and when the block completes it will release it as well, causing the retain count to go to 0 so it will be released.

If nothing above rings a bell or helps, you can at least try and find when/where that object is getting dealloced. Create a UIImageView subclass in your .m file:

@implementation MyIV : UIIMageView
@end
@interface MyIV

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

Put a breakpoint on the log message, and you can see exactly where its getting dealloc'd. I've found this so helpful in the past I created an ARC class to do this even for class clusters on github, called Tracker.

于 2013-05-19T13:38:01.710 回答