Flying alert!

Hello,

What’s wrong with this piece of code, copied/pasted from Apple’s examples? The alert appears very shortly over the window and then the application terminates (without any error).

beginSheetModalForWindow. if you are very fast :slight_smile:

I don’t think you need to return NSTerminateCancel, but should return NSTerminateNow in the case for example that registerModified == NO.

If I understand correctly, the user will have to quit again onces the save is done? You should at least recall applicationShouldTerminate: again when registerModified == NO so the app does quit after saving, or better yet use this to quit: [[NSApplication sharedAppliction terminate:self]

Also, unless I am mistaken, the correct method name for applicationShouldTerminate: is actually this:

- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender

You are passing an NSNotification, not an NSApplication object. Perhaps this explains part of the problem.

And reading the documentation, NSTerminateLater would be a better choice, if I read this correctly:

Helps?

Model: MacBookPro8,2
Browser: Safari 534.51.22
Operating System: Mac OS X (10.7)

Hello leonsimard,

Partly. I’m trying every possibility, apart the good one, apparently.

NSTerminateNow : flashes the alert and quit.
NSTerminateLater : shows the alert and loop eternally, you cannot quit anymore.
NSTerminateNow : shows the alert, dismiss it and refuses to quit.

What I want is:

on quit application
if a file has been modified then
ask user to save changes
if answer is yes then
save changes
end if
end if
quit.

Some of a good old days manner of:
quitCommand:
begin
ierr:=Alert (xxx);
if (ierr = OK) then saveDocument
end;

Seems so simple – but when it comes to the cocoa’s alerts, nothing is simple anymore. I keep exploring.

Thanks anyway!

Hmmm… I see. Have you tried to log a few things here and there to se what’s the path being taken by your app? like one inside the selector being called, and before calling the sheet…

and have you tried to run the alert but not as a sheet? Perhaps this could help…

Already tested that. I put a log in the selector:

2012-05-19 14:07:46.865 Evals7[7304:403] alertDidEnd called

So it’s my app which dismisses the window. I just want my user to get a chance to click on a button :wink:

Apparently, there are lots of questions on the web about these sheets. Nice feature, but. not handy at all.

Did you try not using return NSTerminateCancel (or any other enum) in your fist line? Usually you return somehting when you’re done, the rest of the code should be ignored, probably your app thinks it should dismiss the alert and keep on going… wild guess here.

Objection! It’s very handy when you’ve understood the technique
The usual way to ask for something before quitting the app could look like this.
The contextInfo is not necessary for a single action, you could pass nil.


- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
{
	if (registerModified) {
		NSBeginAlertSheet(NSLocalizedString(@"APPLY_CHANGES", nil), // ask to apply changes
						  NSLocalizedString(@"APPLY", nil), // apply and quit
						  NSLocalizedString(@"DONT_APPLY", nil), // don't apply and quit
						  NSLocalizedString(@"CANCEL", nil), // cancel the whole action (don't apply and don't quit)
						  [NSApp mainWindow],
						  self,
						  @selector(sheetDidEnd:returnCode:contextInfo:), 
						  nil,
						  @"apply",
						  NSLocalizedString(@"ASK_CHANGES", nil));
		return NSTerminateLater;
		
	}
	else
		return NSTerminateNow;
}


- (void)sheetDidEnd:(NSWindow *)sheet
		 returnCode:(NSInteger)returnCode
		contextInfo:(void *)contextInfo
{
	if (contextInfo == @"apply") {
		if (returnCode == NSAlertDefaultReturn) {
			[self applyChanges] // custom method
			[NSApp replyToApplicationShouldTerminate:YES];
		}
		else 
			[NSApp replyToApplicationShouldTerminate:(returnCode == NSAlertAlternateReturn)];	
	}
}


I continue exploring this cocoa’s jungle: how can you make such a simple thing so intricate?!

It is simple

Don’t forget that every user interaction is driven asynchronously to keep the GUI responsive
and avoid expensive polling

:smiley:

Ok, objection accepted, but tell me, about 15 lines in two handlers versus two lines of the ToolBox. :confused:

Well, I got the nice sheet running (in fact I was sure the solution will come from you). I’m not sure to get this “context info” parameter (I read the docs about it, but it’s still unclear), is it a way for passing a block of informations by pointer? And why is it so frequently ignored? Is it provided in case the application will need more private informations?

For sure, Rome wasn’t built in one day. :frowning:

Thanks!

contextInfo is needed if you use a single sheet for multiple requests to distinguish the cases in the endSheet method.
You can pass any object as a void pointer, but in some cases you have to take care of retaining the object.
However a literal string (pointer) is noncritical

The best code is the most effective code not the shortest :wink:

Right – one-liners are really difficult to decipher when you try to retrieve the brilliant idea you had ten years before. And the language does not matter :cool:

I don’t understand how your original code showed a sheet at all – I tried it and got no sheet. Shouldn’t that first line, “return NSTerminateCancel;” keep anything else in your method from running?

Ric

correct… When you have a return in you function/method the code after that won’t get executed. If an dialog is shown it means that there is some code somewhere else that’s been executed. Maybe he used the ‘will’ handler as well.

Hi Ric!

I added this line in despair, just to have a chance to freeze the window on the screen. Oh, yes, I had it – I couldn’t get rid of it.

Fortunately, I don’t have much alerts (I understand the idea to stop only one window, or one application, and let the user work on others, but this way to throw an alert window and then recover the answers.) See, if I have a button to delete an item in the list, I end up with 3 handlers:

an IBAction invoked by the “delete button”, throwing an alert, sort of "requestToDeleteAnItem (id)sender;
a “dismiss” handler to order out the alert and check the result, which has to check “which alert has called me?”
an instance method to get the job done. Well, naming becomes really important. Why not:
-(void) removeAtLastTheItemThatTheUserWantedToDeleteInTheIBActionAndAfterConfirmation {} :confused:

And it’s just an Alert. Now, I’m fighting with a Window to get some parameters.