begin/commitAnimations vs block-based animations - iphone

I still don't get it why Apple discourages the old method of doing animations and instead says to use blocks.
I mean, how does one realistically stop using the old way? Aren't blocks iOS > 4.0 only? Is one supposed to fill the code with ifs and make two different implementations based on the current device's system version? And why do so since the old method works just fine? Plus the underlying implementation should be the same, right? Is there any reasoning behind this aside from the fact that begin/commit produces ugly code?

The old method works fine, but I think with blocks you have the option to have a completion block. Where as with the old way, the animation begins and the code immediately resumes execution. So something like the following sets the alpha of the view only after the animation to move the frame has completed (in this case nested animation blocks). Once the alpha animation finishes, it then removes the view from the superview.
[UIView animateWithDuration:0.3 delay:0 options:UIViewAnimationCurveEaseOut animations:^(void) {
CGRect frame = self.actionView.frame;
self.actionView.frame = CGRectMake(frame.origin.x, 370, frame.size.width, frame.size.height);
}
completion:^(BOOL finished) {
[UIView animateWithDuration:0.2 delay:0 options:0 animations:^(void) {
[self.blockingView setAlpha:0];
} completion:^(BOOL finished) {
[self.actionView removeFromSuperview];
[self.blockingView removeFromSuperview];
}];
}];
you would have to use [respondsToSelector] to determine if the UIView supports the block method, if not use the old way, and you'd probably have to be creative with timing to reproduce nested animations.

I still don't get it why Apple
discourages the old method of doing
animations and instead says to use
blocks.
Apple wants you to use the latest and greatest techniques. Apple will optimize all it's new iOS releases for the block based animations and probably will add new possibilities only to the blocks based animations. So thats why Apple is pushing you to the block based animations.
I mean, how does one realistically stop using the old way? Aren't blocks iOS > 4.0 only?
Yes, blocks are iOS > 4.0 only. So if your App is designed for iOS 4.0+ only you can use block based animations. Or you could check for the availability of blocks and add the specific animation only for the iOS 4.0+ devices.
Completely stop animating the old way is only realistic if you drop support for iOS 3.
Is one supposed to fill the code with ifs and make two different implementations based on the current device's system version? And why do so since the old method works just fine? Plus the underlying implementation should be the same, right? Is there any reasoning behind this aside from the fact that begin/commit produces ugly code?
Well, if the old method is okay for you and you want to support older (iOS 3) devices. Just use the old way of animating. There's nothing wrong with it, don't put unnecessary if-statements in your code. It only makes things complicated and you win nothing by doing it.
If your App is iOS 4 go with blocks, it's shorter and somewhat cleaned. It also should be easier to maintain, because Apple will not keep updating the old way of animating.
(You always can add the if-statements somewhere in the future if there will be animations you only can do with blocks, and then fallback to another less complex animation with the old methods. But thats something for the future.)

Related

Tracking UIView frame change animation

I have a UITextView that changes it's frame with the animateWithDuration:animations method:
[UIView animateWithDuration:1.5 animations:^{
[_textView setFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height - keyboardSize.height-25)];
}];
Is there any callback that helps me track the height of the UITextView as it animates?
There is no accurate way.
That's because the frame is just set directly. The animation takes care of the transition, but actually there is no transition.
There are some ways of estimating what is the current frame size and for me, the best is the simple math solution using a timer, when the animation started and the animation duration.
But, again, it's probably for the best if you just go another way, as this is certainly going to impact on your code cost and precision.
It's my first post and I don't really know anything that well, just learning and trying to help.
This depends on what you want to do with this thing.
If you want somehow accurate information about your frame, use the presentationLayer. This is a semi-accurate representation of what's actually on the screen. Note that this is in the coordinates of the view (bounds), so you need to convert it to the superview's coordinate system to get the current frame.
CGRect currentTextViewFrame = [_textView.superview convertRect:[_textView.layer.presentationLayer frame] fromView:_textView];
Note however this will be about one drawing loop or more off. If you are trying to base another animation off this it may be problematic and can cause flickering or other delay-induced effects. Also, at least the official documentation says this may not always be very fast and you may want to make the animation yourself if you need this information often due to performance reasons.
[_textView.layer.presentationLayer frame].size.height;
Credit belongs to this anwser.

iOS UIView block animations stop actually animating

I've got a weird issue with using UIView block-based animations. My app contains an assortment of images in scroll views and, after a while of using the app on the device, all animations in UIView animation blocks (such as the one below) stop animating. The animation is processed (in the example code below, the pageView does move) but this change isn't animated and happens instantly.
[UIView animateWithDuration:0.5 animations:^
{
self.pageView.center = CGPointMake(self.view.frame.size.width/2, 704.0/2);
self.pageView.transform = CGAffineTransformIdentity;
}
completion:^(BOOL finished)
{
NSLog(#"complete");
}];
Has anyone else experienced similar behaviour? I'm using an iPad on 5.1 and am wondering if it could be down to iOS version?
Thanks,
Michael
Check your memory usage. I am seeing the same thing you are -- eventually all of the animations stopped working. The animations didn't even run for me, and completion blocks weren't firing.
I found that I was holding on to a number of UIImageViews that weren't visible anymore because I wanted to re-show them later. Removing them and freeing up the UIImage made the problem go away. I now need to figure out how I'm going to get back the images but at least the animations work as expected.
When you're using transforms, animations can have a really unpredictable behavior if you use them separately. To avoid this, you ought to concatenate all your transforms into a single one via CGAffineTransformConcat and animate that single transform.
Try using some animation options and see if that helps?
For example here I'm letting the user interact and letting views redraw themselves during an animation :
[UIView animateWithDuration:0.5
delay:0
options: UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionAllowAnimatedContent
animations:^ {
self.pageView.center = CGPointMake(self.view.frame.size.width/2, 704.0/2);
self.pageView.transform = CGAffineTransformIdentity;
} completion:^ (BOOL finished) {
} ];

GLKViewController: incorrect fps

Hope there are some GLKViewController experts out there because I have some problems :)
Just a quick description of my app. I have a UINavigationController in which I push different screens.
At some point, I get to my game screen which is a subclass of UINavigationController. In this screen, in viewDidLoad I manually create a EAGLContext, GLKView and instantiate a new GLKViewController (to handle my update&draw calls).
I am setting a preferred fps of 30.
The problem is that the first 3-4 update calls come with the correct DT, but then I have 2-3 frames with 1 second between them. I measure the DT using controller.timeSinceLastUpdate.
So I get like:
dt=0.33
dt=0.33
dt=0.33
dt=1.07
dt=1.05
dt=0.33
dt=0.33
After this, I get valid only DT times. I have no idea why those frames have that kind of delay. I measured the time it takes me in the update & draw method, and it's nowhere near 1 second.
Also, I'm not loading any textures/creating any geometry. Everything is done at loading since it is a rather small game.
Also, if I pop the game screen controller and then push back another instance of the game screen, this new GLKViewController will only call my update method aproximately every 1 second.
Did anybody have a problem with the framerate when using GLKViewController?
Thanks,
The problem is that you don't know what else the device is doing between your refreshes :)
You might only spent 0.1s working on the next frame but if there is a memory warning then other bits of your app will also take time to process. I guess that the gl controller will do it's best to keep to the preferred frame rate but if lots is going on in the background then there's not much it can do about it.
As long as you make sure that your code is rendering as fast as possible and isn't spiking in the same way as the framerate then it's not your render path. From your question it sounds like you've already tested that.
The other thing you might want to do is to watch out for other notifications that might be passed into your app (i.e. memory warnings).
Finally, is there a pattern to the slow frames - do they coincide with a new image being loaded or a file access? Have you done as much as possible beforehand? EDIT - rereading your question makes me think that you've already done this, sorry!
Sorry I can't be any more use :(
Ok, so I finally figured it out. It turns out that it's not even related to the GLKViewController (surprise surprise!).
It had something to do with the way I'm displaying the game screen view controller, like this:
GameAreaViewController* gameController = [[GameAreaViewController alloc] init];
[UIView beginAnimations:#"animation" context:nil];
[self.navigationController pushViewController: gameController animated:NO];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.navigationController.view cache:NO];
[UIView setAnimationDuration:0.7f];
[UIView commitAnimations];
SAFE_DEL(gameController);
If I use an animation duration of 0.3f, then I don't get any lag. At 0.5f sometimes I get it and at 0.7 I was always getting it.

why is setAnimationDidStopSelector discouraged?

i saw the following in apples documentation on setAnimationDidStopSelector:
"Use of this method is discouraged in iOS 4.0 and later. If you are using the block-based animation methods, you can include your delegate’s end code directly inside your block."
I tried adding what I was going to put inside the animation stop delegate inside the animation block, but the animation doesn't look the same as when i used setAnimationDidStopSelector.
What is the reason for discouraging the use of setAnimationDidStopSelector?
There are lots of APIs that get deprecated in Cocoa Touch. The framework is fairly young and Apple is still tweaking the underlying code. When it is phrased as in your question it probably means "we are going to put all our effort into making block animations perfect, setAnimationDidStopSelector will at some time in the future be deprecated - do yourself a favor and stop using it now".
It sounds weird that your animation behaves different? Have you done it like this?
[UIView animateWithDuration:1.0
delay: 0.0
options: UIViewAnimationOptionCurveEaseIn
animations:^{
aView.alpha = 0.0;
}
completion:^(BOOL finished){
// Do your setAnimationDidStopSelector stuff here!
}];

Source of UIView Implicit Animation delay?

I have a block of UIView animation code that looks like this:
[UIView beginAnimations:#"pushView" context:nil];
[UIView setAnimationDelay:0];
[UIView setAnimationDuration:.5];
[UIView setAnimationDelegate:self];
[UIView setAnimationWillStartSelector:#selector(animationWillStart)];
view.frame = CGRectMake(0, 0, 320, 416);
[UIView commitAnimations];
The code basically mimics the animation of a ModalView presentation and is tied to a button on my interface. When the button is pressed, I get a long (.5 sec) delay (on iPod Touch...twice as fast on iPhone 3GS) before the animationWillStart: actually gets called. My app has lots going on besides this, but I've timed various points of my code and the delay definitely occurs at this block. In other words, a timestamp immediately before this code block and a timestamp when animationWillStart: gets called shows a .5 sec difference.
I'm not too experienced with Core Animation and I'm just trying to figure out what the cause of the delay is...Memory use is stable when the animation starts and CoreAnimation FPS seems to be fine in Instruments. The view that gets animated does have upwards of 20 total subviews, but if that were the issue wouldn't it cause choppiness after the animation starts, rather than before? Any ideas?
Try it with a single subview or with no subviews at all to make sure the delay is not caused by so many children.
Profile the code in Instruments to see where exactly the code lags. You might get down to some internal Core Animation function call that will hint you what’s going on.
Try the code without the “lot that’s going on” to make sure you’re not stepping on Core Animation’s toes with your other code.
Or, in short: experiment and measure, because conjectures seldom work when optimizing.
In your pasted block, you specify the selector animationWillStart (no colon), but later in your question, you refer to animationWillStart: (with colon). These selectors are not equivalent, so is it possible that your intended selector is never being called on account of this animation, and is being called 0.5 seconds later on account of some other animation?