Animations taking extra memory - objective-c

I need to use animation in my iPad application.When I use the animations the memory is increasing and getting exception..When I launch my application the size of the memory is 10 mb, once the animations are started it is increasing the memory size upto double of the launch space (it is 30 mb). I test for the allocations and leaks everything is perfect but still I got this problem. I don't know why it is happening. My animation code is as follows.Please help me.
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
if ([currentView superview])
{
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:mainView cache:YES];
[currentView removeFromSuperview];
[mainView addSubview:nextView];
}
[UIView commitAnimations];
Thanks in advance,
Sekhar Bethalam.

How sure are you that the animation is causing the leak?
What happens when you add/remove subviews without the animation? Is the leak still there?
Where is nextView initialized/released?
What exactly is if ([currentView superview]) meant to check for because I think it'll always return True?

I'm not sure if it's the method itself that is increasing the memory usage but likely your view controller that's being loaded in?
Also try adding these lines in your animation block as I think it's encouraged (please correct me if I am wrong)
[currentView viewWillAppear:YES];
[currentView viewDidAppear:YES];
[mainView viewWillDisappear:YES];
[mainView viewDidDisappear:YES];
Also I believe setAnimationTransition is now discouraged in IOS4 so maybe try using
+ (void)transitionWithView:(UIView *)view duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion

Related

Alternative to "self" in calling methods in Objective-C

This may sound really noob, but i've spent an entire day wrestling with this problem and would appreciate some help.
You see i have a method which I call more than once inside gameplay. If I use [self myMethod]; then it works for ONE time. And then when I call it again, the animation in the method doesn't commence anymore.
What I need is to replace "self" with an alternative that can be "alloc'ed" and "released" to make my animations work.
I've tried;
#implementation gameViewController
gameViewController *object = [[gameViewController alloc] init];
[object myMethod];
However the above substitute for self doesn't even call on the method. I don't know what I did wrong, it's suppose to work just like "self".
Is there something i missed? How do you make an object of the class to work just like "self" does?
Thanks so much.
Here is a more detailed look of my code;
[self explosionAnimations];
- (void) explosionAnimations
{
UIImage *image = [UIImage imageNamed: #"Yellow Explosion.png"];
[bomb setImage:image];
[UIView beginAnimations:#"bomb1ExplosionIncrease" context:NULL];
[UIView setAnimationDuration:0.5];
[UIView setAnimationDelegate:self];
bomb.transform = CGAffineTransformMakeScale(3.4, 3.4);
[UIView commitAnimations];
}
The setImage works fine every time. But the animations stop working on the second call of the method. While in the console it logs "animation completed" with nothing happening to the image.
This leads me to believe that somehow "self" believes that the animation was already done and will not bother to do it again. So I thought a new "alloc" might give it a kick awake.
The problem doesn't have anything to do with "self". The problem is that you set the transform in your animation, and then when you run it again, you're setting the same transform, so it does nothing. You need to reset the frame to the new frame and then set the transform back to the identity transform before you do the animation again. Also, you should be using block based animations. I'm not sure this is the best way to do it, but this worked for me (if you have auto layout turned off).
- (void)explosionAnimations {
UIImage *image = [UIImage imageNamed: #"Yellow Explosion.png"];
[self.bomb setImage:image];
[UIView animateWithDuration:.5 animations:^{
self.bomb.transform = CGAffineTransformMakeScale(3.4, 3.4);
} completion:^(BOOL finished) {
CGRect newFrame = self.bomb.frame;
self.bomb.transform = CGAffineTransformIdentity;
self.bomb.frame = newFrame;
}];
}
If you're doing this in an app with auto layout turned on (which it is by default), then I would not use a transform, but just resize the width and height of the image view by adjusting its height and width constraints. So, in this method, you should make IBOutlets to height and width constraints you make in IB, then change their constant values in an animation block:
[UIView animateWithDuration:.5 animations:^{
self.heightCon.constant = self.heightCon.constant * 3.4;
self.widthCon.constant = self.widthCon.constant * 3.4;
[self.view layoutIfNeeded];
}];

Use of beginAnimations discouraged

I was informed recently by meronix that use of beginAnimations is discouraged. Reading through the UIView class reference I see that this is indeed true - according to the Apple class ref:
Use of this method is discouraged in iOS 4.0 and later. You should use
the block-based animation methods to specify your animations instead.
I see that a large number of other methods - which I use frequently - are also "discouraged" which means they'll be around for iOS 6 (hopefully) but probably will be deprecated/removed eventually.
Why are these methods being discouraged?
As a side note, right now I'm using beginAnimations in all sorts of apps, most commonly to move the view up when a keyboard is shown.
//Pushes the view up if one of the table forms is selected for editing
- (void) keyboardDidShow:(NSNotification *)aNotification
{
if ([isRaised boolValue] == NO)
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.25];
self.view.center = CGPointMake(self.view.center.x, self.view.center.y-moveAmount);
[UIView commitAnimations];
isRaised = [NSNumber numberWithBool:YES];
}
}
Not sure how to duplicate this functionality with block-based methods; a tutorial link would be nice.
They are discouraged because there is a better, cleaner alternative
In this case all a block animation does is automatically wrap your animation changes (setCenter: for example) in begin and commit calls so you dont forget. It also provides a completion block, which means you don't have to deal with delegate methods.
Apple's documentation on this is very good but as an example, to do the same animation in block form it would be
[UIView animateWithDuration:0.25 animations:^{
self.view.center = CGPointMake(self.view.center.x, self.view.center.y-moveAmount);
} completion:^(BOOL finished){
}];
Also ray wenderlich has a good post on block animations: link
Another way is to think about a possible implementation of block animations
+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations
{
[UIView beginAnimations];
[UIView setAnimationDuration:duration];
animations();
[UIView commitAnimations];
}
Check out this method on UIView, which makes it quite simple. The trickiest part nowadays is not allowing a block to have a strong pointer to self:
//Pushes the view up if one of the table forms is selected for editing
- (void) keyboardDidShow:(NSNotification *)aNotification
{
if ([isRaised boolValue] == NO)
{
__block UIView *myView = self.view;
[UIView animateWithDuration:0.25 animations:^(){
myView.center = CGPointMake(self.view.center.x, self.view.center.y-moveAmount);
}];
isRaised = [NSNumber numberWithBool:YES];
}
}

How to let two animations for UIView executed one by one

I have a small UIView and want to let it move to center of screen first, and then, zoom to full screen.
But when I begin start an animation like
[UIView beginAnimations:#"animation1" context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(showDetailToFullscreen)];
self.currentDetailVC.frame = centerFrame;
[UIView commitAnimations];
And in the same controller, I have a method:showDetailToFullscreen
- (void)showDetailToFullscreen {
CGRect screenFrame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height);
[UIView beginAnimations:#"animation2" context:nil];
[UIView setAnimationDuration:0.5];
self.currentDetailVC.view.frame = screenFrame;
[UIView commitAnimations];
}
but when start, it still executed together.
I think the problem they are still in the same transaction. But how can I let these two animation executed one by one? Appreciate for any answer!
Try this instead of the setAnimationDidStopSelector:
[self performSelector:#selector(showDetailToFullscreen) withObject:nil afterDelay:0.5];
It's now considered much better to annimate views using the 'blocks' methods that can be found in the "Animating Views with Blocks" section in the UIView Class Reference.
In most of these methods you can specify a "completion" block of code that can be used to start off a second animation when the first animation completes. You could also call showDetailToFullscreen within this completion block.
I'd reccommend trying this method instead.
Are you targetting iOS 4 or later? If so, I recommend using the block-based animation methods instead. What you want to do is very easy:
Example from UIView docs:
[UIView animateWithDuration:0.2
animations:^{view.alpha = 0.0;}
completion:^(BOOL finished){ [view removeFromSuperview]; }];

Strange graphics glitch when using flip animation

I'm getting a strange error when committing a flip animation. These three bars show up, almost like strips that aren't being drawn too.
I got a screenshot to show what I'm talking about. These lines are always in the same place, and show up on both sides.
graphics glitch screenshot http://img263.imageshack.us/img263/6079/animationglitch.jpg
Here is the code that I'm using, I've used it before without problems, so I'm not sure whats goin on.
-(void)switchView
{
BOOL isChangingToMapView = _mapViewController.view.superview == nil;
CGContextRef context = UIGraphicsGetCurrentContext();
[UIView beginAnimations:nil context:context];
[UIView setAnimationDuration:1];
[UIView setAnimationTransition:(isChangingToMapView ? UIViewAnimationTransitionFlipFromLeft : UIViewAnimationTransitionFlipFromRight) forView:self.view cache:YES];
if (isChangingToMapView)
{
[_mapViewController viewWillAppear:YES];
[_listViewController viewWillDisappear:YES];
[_listViewController.view removeFromSuperview];
[self.view insertSubview:_mapViewController.view atIndex:0];
[_listViewController viewDidDisappear:YES];
[_mapViewController viewDidAppear:YES];
}
else
{
[_listViewController viewWillAppear:YES];
[_mapViewController viewWillDisappear:YES];
[_mapViewController.view removeFromSuperview];
[self.view insertSubview:_listViewController.view atIndex:0];
[_mapViewController viewDidDisappear:YES];
[_listViewController viewDidAppear:YES];
}
[UIView commitAnimations];
}
Any ideas as to what could be causing this?
Well I banged my head off of this problem for awhile and then moved on. Then I had the bright idea to try it on the actual phone. Sure enough it runs properly on the phone.
Just a little reminder, if you are having weird problems developing on the simulator, at least try your app on the phone before you waste to much time chasing a bug made by the simulator.

UITableView frame height animation glitch

If I attempt to animate the frame height of a tableView (ex: height -= 200), the cells that appear in the last 200px disappear suddenly before the smooth animation of the frame completes.
To make sure that it's nothing else I'm doing, I created a new View-Based application. In the main viewController I create my own tableview with enough pseudo rows to fill the entire screen. And on selection of a row I do a simple height animation.
most relevant code:
- (void)viewDidLoad {
[super viewDidLoad];
self.myTable = [[[UITableView alloc] initWithFrame:CGRectMake(0, 0, 320, 460)] autorelease];
myTable.delegate = self;
myTable.dataSource = self;
[self.view addSubview:myTable];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
CGRect frame = self.myTable.frame;
frame.size.height = 200;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDelay:.5f];
[UIView setAnimationDuration:0.5f];
self.myTable.frame = frame;
[UIView commitAnimations];
}
Does anyone know why this is happening, or what a fix/workaround may be?
Any suggests are really appreciated.
TIA!
I'm not sure I had exactly the same problem, but using [UIView setAnimationBeginsFromCurrentState:YES]; solved (parts of) the glitches (my table view slid around crazily when animating a frame height change).
Same problem here as well. This is what I'm doing and the origin animates smoothly, but the size changes immediately... annoying.
[UIView beginAnimations:#"HideTabbar" context:nil];
[UIView setAnimationDuration:.3];
self.tableView.frame = CGRectMake(0.0, 44.0, 320, 366);
[UIView commitAnimations];
UPDATE: Try adding this before the animation:
self.tableView.autoresizingMask = UIViewAutoresizingNone;
For anyone hitting this question & answer in the future, here's how to use #ryyst's answer in UIView's block based animations introduced in iOS 4.
[UIView animateWithDuration:0.3 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
// change frame etc here
} completion:^(BOOL finished) {
// any clean up here
}];
This is an old question and there are already a couple suggestions for a workaround, but I thought I'd add mine.
I ended up animating the contentInset and scrollIndicatorInsets properties, which provides the illusion that the table itself is being resized.
I have exactly the same problem. I imagine that tableviews have a special behavior on "setFrame:", it seems that the tableview remove the cells that won't be visible with the new frame.
In case of an animation, the cells won't be visible only at the end of the animation, but it seems that tableviews don't care.
If someone have a better theory, I'd be glad to hear it !
Finally found the solution! there is indeed a bug!! don't use variables, when animating the height use [[UIScreen mainScreen] bounds]. Like this:
[UIView animateWithDuration:0.5 animations:^{
tableView.frame=CGRectMake(0, 38, fullScreenRect.size.width, [[UIScreen mainScreen] bounds].size.height-38);
}];
not :
[UIView animateWithDuration:0.5 animations:^{
tableView.frame=CGRectMake(0, 38, fullScreenRect.size.width, fullScreenRect.size.width-38);
}];
and it will work like magic!
I found your question while seeking the proper method to resize a tableView. I think your problem is in your animation you've specified UIView instead of UITableView. I was unable to duplicate your problem using either UIView or UITableView, but I'm using SDK 3.1 and it might be a bug that has been fixed since your post. I'm not sure, but I hope this helps!
It's an old question but this might help someone in the future;
I solved a similar problem by embedding the tableview in a UIView, and resizing the UIView instead of tableview. I set the tableview's height to a large value and also "clip subviews" property on the UIView. I resize the UIView proportional to tableview's contentSize. Its not a good solution but it worked for my purposes.