Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

Littleodie914

macrumors 68000
Original poster
Jun 9, 2004
1,813
8
Rochester, NY
Hey guys, I have the following sections of code that I use to fade out a modal window:

Code:
- (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:

Code:
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:

Code:
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
 
(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 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:

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

Then the window closes properly on 10.5.
 
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.
 
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.
 
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:

Code:
 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):

Code:
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)
 
Attached is a simple project demonstrating the issue. I can confirm the window closes on 10.6, but does not on 10.5.
 

Attachments

  • FadingNSWindow.zip
    27.6 KB · Views: 77
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 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. :eek: 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.
 
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.
 
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....
 

Attachments

  • FadingNSWindow-Modified.zip
    39.9 KB · Views: 71
"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."
 
"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. :(
 
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 ;)
 

Attachments

  • FadingNSWindow-Working.zip
    40 KB · Views: 69
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
 
Nice jared. Forgot about NSViewAnimation. Indeed, many ways to go about this :)
 
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.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.