开发者

Stop recursive function on viewDidUnload

开发者 https://www.devze.com 2023-04-06 17:44 出处:网络
I have a recursive function that plays a UIView animation continuously (if there is a better way to do this, please let me know):

I have a recursive function that plays a UIView animation continuously (if there is a better way to do this, please let me know):

-(void)playAnimationRecursive
{
    [appDelegate commenceFishAnimation];
    [animationView addSubview:appDelegate.fishAnimationImageView];
    animationView.alpha=0.5;

    [NSTimer scheduledTimerWithTimeInterval:14.0 target:self selector:@selector(playAnimationRecursive) userInfo:nil repeats:NO];
}

and not sure if this is neccessary, but here's the appDelegate commenceFishAnimationMethod:

        upperFish=[[UIImageView alloc] initWithImage:upperFishImage];
        bigFish=[[UIImageView alloc] initWithImage:bigFishImage];
        shark=[[UIImageView alloc] initWithImage:sharkImage];
        groupFish=[[UIImageView alloc] initWithImage:groupFishImage];
        fish1=[[UIImageView alloc] initWithImage:fish1Image];
        fishAnimationImageView=[[[UIImageView alloc] init] retain];

        //set the initial position of each fish to be out of frame
        upperFish.frame=CGRectMake(-50, 150, 119/2, 93/2); //moves east
        bigFish.frame=CGRectMake(-280, 340, 251/2, 137/2); //moves east
        shark.frame=CGRectMake(-100, 390, 164/2, 52/2); //moves east
        groupFish.frame=CGRectMake(500, 320, 155/2, 89/2); //moves west
        fish1.frame=CGRectMake(370, 280, 155/2, 89/2); //moves west

        //add fishes to current view
        [fishAnimationImageView addSubview:upperFish];
        [fishAnimationImageView addSubview:bigFish];
        [fishAnimationImageView addSubview:shark];
        [fishAnimationImageView addSubview:groupFish];
        [fishAnimationImageView addSubview:fish1];

        //animate the position of each fish view
        [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationDuration:10.0];
        [UIView setAnimationCurve:UIViewAnimationCurveLinear];
        upperFish.transform=CGAffineTransformMakeTranslation(150, -200);
        bigFish.transform=CGAffineTransformMakeTranslation(600, 0);
        shark.transform=CGAffineTransformMakeTranslation(550, 0);
        groupFish.transform=CGAffineTransformMakeTranslation(-600, 0);
        fish1.transform=CGAffineTransformMakeTranslation(-550, 0);

        [UIView commitAnimations];
        [fishAnimationImageView release];
        [upperFish release];
        [bigFish release];
        [shark release];
        [groupFish release];
        [fish1 release];  
}

So what happens is that every view I have plays this animation in the BG, so if I'm on view A, then it calls the recursive function and plays the animation continuously. If I move to view B, then it calls the recursive function also and plays the animation continuously. However, I'm getting memory warning level 2, and I'm thinking maybe it's because view A is still calling the recursive method? If that is the reason, then how would I stop the recursive method on unload? Or is that not my problem?

EDIT:

Here's my code now (animation doesn't loop)

-(void)commenceFishAnimation
{
    UIImageView *newImageView=[[UIImageView alloc] init];
    self.fishAnimationImageView=newImageView;

    upperFish=[[UIImageView alloc] initWithImage:upperFishImage];
    bigFish=[[UIImageView alloc] initWithImage:bigFishImage];
    shark=[[UIImageView alloc] initWithImage:sharkImage];
    groupFish=[[UIImageView alloc] initWithImage:groupFishImage];
    fish1=[[UIImageView alloc] initWithImage:fish1Image];

    //set the initial position of each fish to be out of frame
    upperFish.frame=CGRectMake(-50, 150, 119/2, 93/2); //moves east
    bigFish.frame=CGRectMake(-280, 340, 251/2, 137/2); //moves east
    shark.frame=CGRectMake(-100, 390, 164/2, 52/2); //moves east
    groupFish.frame=CGRectMake(500, 320, 开发者_运维技巧155/2, 89/2); //moves west
    fish1.frame=CGRectMake(370, 280, 155/2, 89/2); //moves west

    //add fishes to current view
    [fishAnimationImageView addSubview:upperFish];
    [fishAnimationImageView addSubview:bigFish];
    [fishAnimationImageView addSubview:shark];
    [fishAnimationImageView addSubview:groupFish];
    [fishAnimationImageView addSubview:fish1];

    //animate the position of each fish view
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:10.0];
    [UIView setAnimationCurve:UIViewAnimationCurveLinear];
    upperFish.transform=CGAffineTransformMakeTranslation(150, -200);
    bigFish.transform=CGAffineTransformMakeTranslation(600, 0);
    shark.transform=CGAffineTransformMakeTranslation(550, 0);
    groupFish.transform=CGAffineTransformMakeTranslation(-600, 0);
    fish1.transform=CGAffineTransformMakeTranslation(-550, 0);

    [UIView setAnimationDelegate:self];
    [UIView setAnimationDidStopSelector:@selector(commenceFishAnimation)];
    [UIView commitAnimations]; 

    [fishAnimationImageView release];
    [upperFish release];
    [bigFish release];
    [shark release];
    [groupFish release];
    [fish1 release];
    //[newImageView release]; //if I release it, then my animation doesn't play for some reason
}

Then in some other class in the viewDidLoad method, I do this:

[appDelegate commenceFishAnimation];
[animationView addSubview:appDelegate.fishAnimationImageView];

But the animation only plays once.


That's not the best way chaining animations, use this instead:

    [UIView setAnimationDidStopSelector:@selector(playAnimation)];

That will chain your animations in an infinite loop.

But also note that in your method playAnimationRecursive you are adding subviews and scheduling a NSTimer every 14 seconds without releasing them. Thats a really bad idea.

To sum up: forget about recursion and use the method above.

EDIT: I forgot to mention that you have to assign the delegate of the animation:

[UIView setAnimationDelegate:self];  //self or whatever implements playAnimation selector


I see a few red flags that suggest you don't have a good understanding of reference counting in Objective C.

[[[UIImageView alloc] init] retain];

Never do that. alloc already gives you a reference count of 1. You don't need to retain it also.

fishAnimationImageView=[[[UIImageView alloc] init] retain];

Uh-oh, what happened to the previous object referenced by fishAnimationImageView? It is still retained, but nobody has a reference to it. Leak!

[fishAnimationImageView release];

Technically correct, since you double-retained it before, but you should normally not release that object because it is (I assume) an instance variable of your app delegate.

Here is what you should do.

UIImageView *newFishAnimationImageView = [[UIImageView alloc] init];
// retain count = 1
self.fishAnimationImageView = newFishAnimationView;
// retain count = 2
// old value retain count = 0
// assuming a typical property declaration as retain, and setter made by @synthesize
[newFishAnimationView release];
// retain count = 1; not owned locally, but owned by your app delegate

Referring to things by their properties typically gets you the correct reference counting behavior. Follow that, and the rule of releasing anything you alloc, and there aren't many cases where you will go wrong.

You should probably review the documentation on reference counting.

Also, try out Product > Profile in XCode, and pick Leaks. It can tell you if you have memory leaks and where they are.

0

精彩评论

暂无评论...
验证码 换一张
取 消