CABasicAnimation lag issues with IOS 5 and RemoteIO - iphone

I am creating a musical instrument for the iPhone. In my app when i touch a CALayer a note plays and the layer does a wiggle for the duration of the note.
This was all working perfectly on iOS 4.1, however I just upgraded to iOS 5.0.1 and experienced major lag issues if I pressed multiple notes in succession. After much pain I have narrowed it down to the following wiggle animation code for the CALayer that is touched.
// here is an example wiggle
CABasicAnimation *wiggle = [CABasicAnimation animationWithKeyPath:#"transform"];
wiggle.duration = 0.1;
//wiggle.repeatCount = 1e100f;
wiggle.repeatCount = 100;
wiggle.autoreverses = YES;
wiggle.toValue = [NSValue valueWithCATransform3D:CATransform3DRotate(fret.fretLayer.transform,0.2, 0.0 ,1.0 ,2.0)]; //angle, x , y , z
wiggle.fromValue = [NSValue valueWithCATransform3D:CATransform3DRotate(fret.fretLayer.transform,-0.2, 0.0 ,1.0 ,2.0)]; //angle, x , y , z
// doing the wiggle
[note.noteLayer addAnimation:wiggle forKey:#"wiggle"];
If I block out the last line where the animation is added to the layer all lag disappears immediately. It feels like the main thread is being blocked somehow, or its not running on the main thread, but I have tried invoking the function with performSelectorOnMainThread:withObject:waitUntilDone:NO and it made no difference. If I press loads of notes really quickly the whole app pauses, and then a second or so later its like it catches up with itself and suddenly all the sound plays and the animation finally begins all choppy and choked after that.
Does anyone know of any unusual issues with CABasicAnimation in iOS 5? Is there any alternative animation APIs that I could try that could also animate CALayers for an unspecified duration on repeat? Anyone have any suggestions or guesses as to how to fix/what the problem could stem from?
EDIT:
I have determined it is definitely nothing to do with nature of the animation. I replaced the wiggle code with code that simply fades the colour like so, but I am still getting the same lag effect with notes being laggy to play.
CABasicAnimation *wiggle = [CABasicAnimation animationWithKeyPath:#"backgroundColor"];
wiggle.duration = 2;
wiggle.toValue = (id)[UIColor whiteColor].CGColor ;
wiggle.fromValue = (id)[UIColor colorWithRed:0.1 green:0.2 blue:0.8 alpha:0.4].CGColor;
Suspect it could be something to do with a change in CoreAudio/RemoteIO perhaps? And that is interfering with the main thread or visa versa?

Finally worked out the true nature of what was causing the issue. Turns out there is a problem with using shouldRasterize = YES in iOS 5.
In my app I am embedding 100+ CALayers in a UIView which has had its layer set to shouldRasterize = YES. I created a new app from the ground up and added bits in until i replicated the problem. Ultimately it turned out to be this. In iOS 4 this isnt a problem. In iOS 5 it is. If I turn shouldRasterize off the problem disappears immediately.
Have submitted a bug report with apple.

Just for test, try to replace CABasicAnimation with [UIView beginAnimation/commitAnimation].

Related

Animating Background image /layer in iPhone

I started working on sample application, where I have some objects(images) which are animated on a UIView. I would like to have a background image which also should animate along with these objects.Two animations should happen at the same time. The background image occupies all the screen space and on the top of this the other images should be animated. Could someone guide me to achieve this.
I tried the following things mentioned in the link below.
for (int i = 0; i < IMAGE_COUNT; i++)
[_imageArray addObject:[UIImage imageNamed:[NSString stringWithFormat:#"D%d.png", i]]];
_animatedImages = [[UIImageView alloc]
initWithFrame:CGRectMake(
(SCREEN_WIDTH / 2) - (IMAGE_WIDTH / 2),
(SCREEN_HEIGHT / 2) - (IMAGE_HEIGHT / 2) + STATUS_BAR_HEIGHT,
IMAGE_WIDTH, IMAGE_HEIGHT)];
_animatedImages.animationImages = [NSArray arrayWithArray:_imageArray];
_animatedImages.animationDuration = 1.0;
_animatedImages.animationRepeatCount = -1;
The iPhone Game Background as Video or Animated Image?
But two animations are happening independently. I would like to animate the objects on the top of background image which also need to be animated.If this is not possible can I use layers or some other object to achieve this.Please suggest.
It seems like `UIImageView' provides no way to control the time the animation begins.
There is such an API, but it's in lower level CoreAnimation framework (which UIImageView must use in its implementation...)
You could re-implement you own UIImageView animation.
Then, to set different animations with relative timing, see "How can I chain Core Animations for different Layers one after the other?"
and How to group two CABasicAnimation animations and kick them off at the exact same time?.
As you don't need an offset between all your layers animations but want them to run at the same time, you should create a CAAnimationGroup, and put all of them with the same beginTime.
The CAMediaTiming protocol (implemented by CAAnimation) is pretty baldy documented - but this is the part you're interested in : timing your Core Animations - Check this post for some API clarification

Blurry UIView with CATransform3D only on RETINA

I'm displaying a UIView with a UILabel on it and this view&label become blurry as soon as it gets to these lines code:
CATransform3D transform = CATransform3DIdentity;
transform.m34 = (1.0/-500);
view.layer.transform = transform;
Throughout the App I use CA3DRotations and other stuff and this never happened before.
Also, I set the frame of the view and the label only using integers! So it's not a half-pixel problem or something like that, I know that that causes most blurry problems, but not mine!
On the simulator it's not blurry, iPad is not blurry, iPhone3GS is not blurry. Only on an iPhone4 with Retina display it becomes blurry. Even before I do any 3D rotations! Does anybody have a clue before I go insane?
Alright, I've found a solution.
After using a hundred different lines of code using layer properties, such as layer gravity or magnification and tons of other solutions I suddenly stumbled by accident on the following 2 lines:
self.layer.shouldRasterize = TRUE;
self.layer.rasterizationScale = [[UIScreen mainScreen] scale];
This is the solution! For everyone in the future, is your view blurry on retina displays? Use this!
Have you set the contentsScale for the layer to match [UIScreen mainScreen]. scale? Try it.
It's possible your views are 'between pixels' (eg. center is [12.5, 10]). Try rounding their location and see if that helps.
If your final landing position is intended to be flat/untransformed, simply setting the transform to CATransform3D identity will also fix the problem. Depending on how things are animated, setting a final position for one of the 3D transforms to 0.0 can still introduce rounding errors and give a fuzzy appearance.

CATransiton Flicker w/ background animations

I am using a CATransition to shuffle CALayer's in and out of a UIView (the UIView isn't fullscreen.) The new layer enters from the right and the old layer leaves to the left. The CAlayer's have their contents properties set to CGImageRefs. Here is what I believe to be the pertinent code:
CATransition *transition = [CATransition animation];
transition.duration = transitionTime;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionPush;
transition.subtype = kCATransitionFromRight;
transition.delegate = self;
[view.layer addAnimation:transition forKey:nil];
// onDeck is the layer stage-right and is about to enter
[view.layer addSublayer:onDeck];
// onStage is the layer currently in the middle of the view and is exiting
if (onStage)
[onStage removeFromSuperlayer];
This animation occurs, there is a 1 second pause, and then a new image is animated in etc, etc. This works beautifully in the simulator but on my 2nd generation iPod Touch, there are occasional hiccups in the animation. Specifically, the layer being animated in will flicker on top of the currently displayed layer. These flickers are not consistent but are noticeable.
What I've narrowed down to be the likely culprit(s) are the background animations I have going on behind this transition. There are a few dozen CAlayer's flying in and out of the full-screen view in the background. When I remove these background animations or set the animation duration for the transition to a much higher duration (2 seconds +) the animation performs fine (I'd like the animation time to be 0.75 seconds.)
My first thought (which seems to be backed up by the above observations) is that I am pushing CoreAnimation (at least for my iPod) too hard and need to compromise. Why I am having trouble accepting this is that the scene renders very nicely (little to no lag) aside from this occasional flicker.
If anyone has any input on this issue, or CoreAnimation optimization in general, I'd be very much appreciative!
Thanks for reading
Update:
Had a chance to test this on an iPhone 4 and the flickering never occurred. Additionally, CoreAnimation instrument confirmed that, on my 2nd generation iPod Touch, I am consistently getting high 40s to low/mid 50s in FPS.
Just a guess: have you tried managing your CATransactions at all?
You might try bracketing your modifications to the scene like this:
[ CATransaction begin ]
... your animations ...
[ CATransaction commit ] ;
I would get rid of all shadows (if you have any) and then check if performance improves. I've seen that shadows, particularly shadows on CAShapeLayers, have a great impact on the smoothness of animations.

Hidden CATransition animations on iOS 4 (camera iris animation)

I'm trying to achieve the camera iris animation from the Apple camera app. It is also found in numerous other apps like RedLaser, Sudoku Grab, so it seems to be fine with Apples rules even thou it's private.
The hidden CATransition animations are dokumented here for example:
http://iphonedevwiki.net/index.php/UIViewAnimationState
However I'm not able to get any of the hidden ones to work, public ones work fine thou. Could this be a change of iOS 4? All information I do find on those hidden animations seems a little dated.
Here is my code:
CATransition *animation = [CATransition animation];
animation.delegate = self;
animation.duration = 2.0;
animation.timingFunction = UIViewAnimationCurveEaseInOut;
animation.type = #"cameraIris";
[self.window.layer addAnimation:animation forKey:nil];
Using "reveal" as 'animation.type' works fine with my code.
Has anybody played around with those on iOS 4 yet? Or is the issue totally different?
RedLaser uses this effect on iOS 4 (it's not an iOS 4 optimised app thou).
The animation is found in these other apps because it is Apple's implementation. Accessing the camera API will cause the shutter opening animation to appear. If you want to use this animation for your app in a non-camera api related way, then you will have to roll your own animation.

How can I replicate the trashing animation of Mail.app

In my iPhone app, I have put a UIBarBUtton of type UIBarButtonSystemItemTrash in my UIToolBar. When pressed, I'd like to replicate the animation of Mail.app: the bin opens, the UIView folds and flies into it.
Is there a way to access this animation ithrough the iPhone SDK?
Presently I am using a custom made animation, but there are some limits; for example, I cannot animate the bin itself.
Do you have any suggestion? Code samples?
Cheers,
Davide
Use the suckEffect type on an animation. Also: spewEffect, genieEffect, unGenieEffect, twist, tubey, swirl, cameraIris, cameraIrisHollowClose, cameraIrisHollowOpen, rippleEffect, charminUltra, zoomyIn, and zoomyOut. Doesn't work in the simulator.
CATransition *animation = [CATransition animation];
animation.type = #"suckEffect";
animation.duration = 2.0f;
animation.timingFunction = UIViewAnimationCurveEaseInOut;
view.opacity = 1.0f;
[view.layer addAnimation:animation forKey:#"transitionViewAnimation"];
Note: Code snippet was pulled from a larger codebase. I hope it works :)
Just to add some info:
You can use "suckEffect" with the standard +[UIView setAnimationTransition:forView:cache:]. Just pass the number 103 to the animationTransition variable. This won't avoid your app being rejected by Apple though :p
"spewEffect", "genieEffect", "unGenieEffect", etc. no longer exist on iPhoneOS 3.x. The only undocumented transition left are "cube" (--), "rippleEffect" (110), the three "cameraIris" effects (105,106,107) and "suckEffect" (103).
See http://www.iphonedevwiki.net/index.php?title=UIViewAnimationState for detail.
Also, to animate the bin (with private API): http://www.iphonedevwiki.net/index.php?title=UIToolbar#Animating_the_trash_can_icon.
Unfortunately, I think this is going to need to be an entirely custom animation. The UIView folding can be approximated using Core Animation, perhaps by adding perspective to the CATransform3D of the UIView's underlying layer to distort the UIView into a trapezoid which gets sucked into the trash can.
As far as the trash can, you can create a UIBarButtonItem using initWithCustomView:, which might let you insert a custom UIView that has an animatable trashcan. It looks like the trash can has two elements, the can base and the lid, which are rotated independently to open and close the can. Draw PNGs for both, make UIImageViews for them, and make them subviews of the UIBarButtonItem custom view. For opening and closing, apply rotational transforms to them to animate the subviews.
I'm not sure if this is an answer but here is lib that do "genie effect" so it's quite similar to what you want achieve.
CGRect endRect = CGRectMake(30, 40, 50, 60);
[view genieInTransitionWithDuration:0.7
destinationRect:endRect
destinationEdge:BCRectEdgeTop
completion:^{
NSLog(#"I'm done!");
}];