PDA

View Full Version : Discrepancy using CAAnimation on 10.5 vs 10.6




Littleodie914
Nov 2, 2010, 09:28 AM
Hey guys, I have the following sections of code that I use to fade out a modal window:

- (IBAction)open:(id)sender {
if ([self alphaValue] < 1.0) {
[self setAlphaValue:1.0];
}
[self showDevicesViews];
[self start];
[NSApp runModalForWindow:self];
NSLog(@"runModalForWindow: returned");
[super orderOut:nil];
}

- (void) animationDidEnd:(NSAnimation *)animation {
NSLog(@"animationDidEnd:");
}

- (void)animationDidStop:(NSAnimation *)animation {
NSLog(@"animationDidStop:");
}

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
NSLog(@"animationDidStop:finished:");
[NSApp stopModal];
}

- (void)orderOut:(id)sender {
NSLog(@"self orderOut:");
[self stop];
CAAnimation *anim = [CABasicAnimation animation];
[anim setDelegate:self];
[anim setDuration:0.2];
[self setAnimations:[NSDictionary dictionaryWithObject:anim forKey:@"alphaValue"]];
[[self animator] setAlphaValue:0.0];
}

The issue in a nutshell is that on 10.5, the window never fades out, or even closes. On 10.6, everything works fine.

On 10.6, I see in the console:

11/2/10 10:25:51 AM Application[204] self orderOut:
11/2/10 10:25:51 AM Application[204] animationDidStop:finished:
11/2/10 10:25:52 AM Application[204] runModalForWindow: returned

On 10.5, all I see is:

11/2/10 10:27:31 AM Application[204] self orderOut:


I've read through the documentation for CAAnimation, etc. but I can't find anything that would suggest the behavior for running animations and calling delegate methods would differ between operating system versions.

Am I missing something? Is there a more elegant/proper way to fade out a modal window? I would like to use the "official" method, as opposed to putting together a workaround. Thanks! :D



jared_kipe
Nov 2, 2010, 12:11 PM
(I really only know CocoaTouch)

First off, what are you subclassing?

What is -start and -stop supposed to accomplish? Are they similar to UIAlertView's -show and -dismissWithClickedButtonIndex:animated: ??


If so, possibly move [self stop]; to be after the animation.

Littleodie914
Nov 2, 2010, 12:16 PM
(I really only know CocoaTouch)

First off, what are you subclassing?

What is -start and -stop supposed to accomplish? Are they similar to UIAlertView's -show and -dismissWithClickedButtonIndex:animated: ??


If so, possibly move [self stop]; to be after the animation.I'm subclassing NSPanel.

Start and stop are used for purposes unrelated to the panel's lifecycle, they actually stop listening for bonjour services on the network.

It's definitely an issue with the animation delegate method not being properly called. If I remove the animation code to read:

- (void)orderOut:(id)sender {
NSLog(@"self orderOut:");
[self stop];
[NSApp stopModal]; // New Line
/* <- Start Comment
CAAnimation *anim = [CABasicAnimation animation];
[anim setDelegate:self];
[anim setDuration:0.2];
[self setAnimations:[NSDictionary dictionaryWithObject:anim forKey:@"alphaValue"]];
[[self animator] setAlphaValue:0.0];
*/ <- End Comment
}

Then the window closes properly on 10.5.

jared_kipe
Nov 2, 2010, 12:59 PM
When you created and displayed your panel did you -setWorksWhenModal: YES??

Littleodie914
Nov 2, 2010, 01:16 PM
When you created and displayed your panel did you -setWorksWhenModal: YES??Yep, double-checked, but still no go. :(

jared_kipe
Nov 2, 2010, 01:24 PM
Check that [self animator] returns an actual object.

EDIT meaning something like NSLog(@"%@", [self animator]); say.. right after the NSLog(@"self ourderOut:");
EDIT2 also, it couldn't hurt to do [self setAlphaValue: 1.0]; around the same time.
EDIT3 is your panel interface explicitly SAY it implements whatever delegate protocol is used here. Maybe that is something Apple could have changed in the implementation of the CAAnimation stuff when going from 10.5 -> 10.6
Maybe in 10.5 the call back methods use -conformsToProtocol: and in 10.6 they uses -respondsToSelector: for each method. That would explain what we are seeing here most succinctly.

kainjow
Nov 2, 2010, 01:27 PM
Few things to try:

- Override +defaultAnimationForKey: and return your CABasicAnimation instance there.
- Use NSAnimationContext instead. You don't get the delegate callback but easy to workaround with a timer.
- Use NSTimer, add it to NSEventTrackingRunLoopMode and NSModalPanelRunLoopMode and call setAlphaValue: repeatedly.

Littleodie914
Nov 2, 2010, 02:14 PM
Check that [self animator] returns an actual object.

EDIT meaning something like NSLog(@"%@", [self animator]); say.. right after the NSLog(@"self ourderOut:");I'll test this and get back to you in a second. (I have both 10.5 and 10.6 on the same machine, have to reboot.)

Edit: No dice. On 10.6:

2010-11-02 15:02:46.335 Application[254:a0f] self orderOut:
2010-11-02 15:02:46.337 Application[254:a0f] animator: <_NSWindowAnimator_SyncPanel: 0x177750> Animator Proxy for: {
<SyncPanel: 0x124fc0>
}
2010-11-02 15:02:46.540 Application[254:a0f] animationDidStop:finished:
2010-11-02 15:02:47.153 Application[254:a0f] runModalForWindow: returned


And on 10.5 (just noticed my timezone is messed up... crappy dual boot):

11/2/10 12:16:09 PM Application[100] self orderOut:
11/2/10 12:16:09 PM Application[100] animator: <_NSWindowAnimator_SyncPanel: 0x1be9f0> Animator Proxy for: {
<SyncPanel: 0x15f8b0>
}


EDIT3 is your panel interface explicitly SAY it implements whatever delegate protocol is used here. Maybe that is something Apple could have changed in the implementation of the CAAnimation stuff when going from 10.5 -> 10.6
Maybe in 10.5 the call back methods use -conformsToProtocol: and in 10.6 they uses -respondsToSelector: for each method. That would explain what we are seeing here most succinctly.As far as I can tell, there is no formal protocol. You just set the delegate on the animation, then implement the proper methods. I'm not even sure where I found reference of the animationDidStop:finished: method. :confused:

Documentation (May Require Login) (http://developer.apple.com/library/ios/#documentation/GraphicsImaging/Reference/CAAnimation_class/Introduction/Introduction.html)

Littleodie914
Nov 2, 2010, 02:32 PM
Attached is a simple project demonstrating the issue. I can confirm the window closes on 10.6, but does not on 10.5.

jared_kipe
Nov 2, 2010, 02:34 PM
I assume you tried my EDIT2 solution as well?'

EDIT: I have no machines running 10.5, not even sure any of my machines CAN run 10.5 at this point.

Littleodie914
Nov 2, 2010, 02:40 PM
I assume you tried my EDIT2 solution as well?'

EDIT: I have no machines running 10.5, not even sure any of my machines CAN run 10.5 at this point.I have tried your EDIT2 solution, but unfortunately it didn't help.

I had to partition my hard drive and whip out my old restore CDs to install Leopard.

I was actually having a friend test the application last night, and her laptop only has 10.5. Since the modal window never closes, she ended up having to force quit the app. :o Good thing we found it though! I had assumed things would behave the same on 10.5 and 10.6, guess it was a foolish assumption to make.

kainjow
Nov 2, 2010, 03:27 PM
I played around a bit. Definitely related to the modal run loop. Somehow the animation is just not going through. I tried with NSAnimationContext and a timer but no luck.

I would either drop the animation for 10.5 since most people are on 10.6 now or switch to NSTimer where you have much more control.

jared_kipe
Nov 2, 2010, 03:28 PM
I have made some changes to your source, you now hit a button {setup} before firing the animation. See if it helps. I wish I had a computer running 10.5 to test with. Maybe I can install something on one of my spare hack boxes around here....

jared_kipe
Nov 2, 2010, 03:36 PM
"On 10.5, NSView and NSWindow property animations that were scheduled through the view’s/window’s “animator”, and that were evaluated by AppKit (rather than being delegated to Core Animation for threaded asynchronous evaluation), were scheduled for updating in the NSDefaultRunLoopMode.
On 10.6, such animations are now evaluated in NSRunLoopCommonModes."

Littleodie914
Nov 2, 2010, 03:52 PM
"On 10.5, NSView and NSWindow property animations that were scheduled through the view’s/window’s “animator”, and that were evaluated by AppKit (rather than being delegated to Core Animation for threaded asynchronous evaluation), were scheduled for updating in the NSDefaultRunLoopMode.
On 10.6, such animations are now evaluated in NSRunLoopCommonModes."Where did you find mention of this? Very interesting.

Also, not to sound stupid, but what exactly does that mean? :) I have no experience with the different run loops.

Edit: Also, I appreciate the modified project, but it still has the same behavior as the original under 10.5. :(

jared_kipe
Nov 2, 2010, 05:37 PM
As expected given that I didn't find out about the run loop thing until after making some changes.

I have fixed the project more appropriately. Using NSViewAnimation in blocking mode.

I HOPEEEEEEE this works in 10.5...... Probably even 10.4 ;)

Littleodie914
Nov 2, 2010, 06:39 PM
As expected given that I didn't find out about the run loop thing until after making some changes.

I have fixed the project more appropriately. Using NSViewAnimation in blocking mode.

I HOPEEEEEEE this works in 10.5...... Probably even 10.4 ;)You, sir, are a gentleman and a scholar. Works perfectly in 10.5 and 10.6. :)

It seems strange (confusing?) that there are so many different ways to accomplish the same thing. (NSViewAnimation, CABasicAnimation, the animator layer, etc.)

Anyway, I'll sleep well tonight. Thanks again. :D

kainjow
Nov 2, 2010, 08:15 PM
Nice jared. Forgot about NSViewAnimation. Indeed, many ways to go about this :)

jared_kipe
Nov 3, 2010, 09:32 AM
Great, glad it worked out. I certainly learned some things (again I'm only really familiar with iOS UI Classes), so good times by all.

I'm also glad apple "fixed" it themselves in 10.6 but wish they had made a 10.5 point release that would have fixed it there too.