|
|
 | | From: | ettore | | Subject: | modal panel (NSRunAlertPanel) doesn't get closed | | Date: | Tue, 28 Dec 2004 19:59:51 GMT |
|
|
 | I occasionally experience a problem with modal alert panels. I create one with:
NSRunAlertPanel(alertTitle, alertMsg, @"Understood", nil, nil);
where alertTitle and alertMsg are 2 NSStrings correctly created with [NSString stringWithFormat: ...].
The problem is that very rarely, with no reproducible pattern, the panel doesn't get closed once the user clicks on the button. It just sits there. The application reacts as the panel has been closed, because I am even able to select other windows and fully use the app as if the panel was closed. When the application needs to open another alert panel (created with the same call) the old one is finally closed but the new one takes its place, with an identical behavior.
My application is a document based application - I am not sure what other information I should provide because the function call seems straightforward, and I don't know what can be related to it..... did anybody ever experience this?
Thank you in advance.
Ettore
|
|
 | | From: | Michael Ash | | Subject: | Re: modal panel (NSRunAlertPanel) doesn't get closed | | Date: | Wed, 29 Dec 2004 04:54:05 -0600 |
|
|
 | ettore wrote: > I occasionally experience a problem with modal alert panels. I create one with: > > NSRunAlertPanel(alertTitle, alertMsg, @"Understood", nil, nil); > > where alertTitle and alertMsg are 2 NSStrings correctly created with > [NSString stringWithFormat: ...].
I don't know if this is actually causing your problem, but here goes.
You should never pass an arbitrary string as the alertMsg in NSRunAlertPanel. It expects alertMsg to be a format string, with the arguments for it to follow the otherButton title. If alertMsg happens to have any format string escapes in it, NSRunAlertPanel will try to decode them and bizarre things could happen. Try changing your code like this:
NSRunAlertPanel(alertTitle, @"%@", @"Understood", nil, nil, alertMsg);
If that doesn't fix it, watch your run log/debugger console to see if any messages are appearing.
|
|
 | | From: | ettore | | Subject: | Re: modal panel (NSRunAlertPanel) doesn't get closed | | Date: | Thu, 30 Dec 2004 08:34:50 GMT |
|
|
 | On 2004-12-29 02:54:05 -0800, Michael Ash said:
> You should never pass an arbitrary string as the alertMsg in > NSRunAlertPanel. It expects alertMsg to be a format string, with the > arguments for it to follow the otherButton title. If alertMsg happens > to have any format string escapes in it, NSRunAlertPanel will try to > decode them and bizarre things could happen. Try changing your code > like this: > > NSRunAlertPanel(alertTitle, @"%@", @"Understood", nil, nil, alertMsg);
Thank you for this, I didn't consider it.
Well, the way I wrote my code should make it so that my alertMsg string (2nd parameter of NSRunAlertPanel) is never supposed to be a format string: in other words, if it happens to be, it's a non-wanted buggy behavior. So, if I understand your suggestion correctly, is your advice just a safe precaution in case there's a bug in my code? In fact I checked the Apple documentation and both A. Hillegaas' book "Cocoa Programming for Mac OS X" and "Cocoa Programming" by Anguish/Buck/Yacktman but I was unable to find an official recommendation to do so.
Anyway, I will give it a try. :)
> If that doesn't fix it, watch your run log/debugger console to see if > any messages are appearing.
Yes, I'll definitively keep an eye there and possibly print the alertMSg string.
Ettore
-- http://cubelogic.org/ Please support Free Software: http://www.gnu.org/philosophy/
|
|
 | | From: | Michael Ash | | Subject: | Re: modal panel (NSRunAlertPanel) doesn't get closed | | Date: | Thu, 30 Dec 2004 15:55:55 -0600 |
|
|
 | ettore wrote: > On 2004-12-29 02:54:05 -0800, Michael Ash said: > >> You should never pass an arbitrary string as the alertMsg in >> NSRunAlertPanel. It expects alertMsg to be a format string, with the >> arguments for it to follow the otherButton title. If alertMsg happens >> to have any format string escapes in it, NSRunAlertPanel will try to >> decode them and bizarre things could happen. Try changing your code >> like this: >> >> NSRunAlertPanel(alertTitle, @"%@", @"Understood", nil, nil, alertMsg); > > Thank you for this, I didn't consider it. > > Well, the way I wrote my code should make it so that my alertMsg string > (2nd parameter of NSRunAlertPanel) is never supposed to be a format > string: in other words, if it happens to be, it's a non-wanted buggy > behavior. So, if I understand your suggestion correctly, is your advice > just a safe precaution in case there's a bug in my code? In fact I > checked the Apple documentation and both A. Hillegaas' book "Cocoa > Programming for Mac OS X" and "Cocoa Programming" by > Anguish/Buck/Yacktman but I was unable to find an official > recommendation to do so.
So barring the possibility of bugs, alertMsg will never contain a % character? Even something like "23% done" will cause strange behavior as the format string parser picks up "% d" and tries to replace it with an integer from the nonexistent argument list.
Anyway, specifying @"%@" and then putting your string in the argument list is always safer in this kind of situation. Even if you're completely sure that there will never be any format string characters, that could change after you forgot about this bit of code.
My suggestion wasn't based on the expectation that you're doing something wrong here, it's just the only possibility I could see.
|
|
 | | From: | e | | Subject: | Re: modal panel (NSRunAlertPanel) doesn't get closed | | Date: | Wed, 12 Jan 2005 11:26:01 GMT |
|
|
 | >ettore wrote: >> On 2004-12-29 02:54:05 -0800, Michael Ash said: >> >>> You should never pass an arbitrary string as the alertMsg in >>> NSRunAlertPanel. It expects alertMsg to be a format string, with the >>> arguments for it to follow the otherButton title. If alertMsg happens >>> to have any format string escapes in it, NSRunAlertPanel will try to >>> decode them and bizarre things could happen. Try changing your code >>> like this: >>> >>> NSRunAlertPanel(alertTitle, @"%@", @"Understood", nil, nil, alertMsg); >> >> Thank you for this, I didn't consider it. >> >> Well, the way I wrote my code should make it so that my alertMsg string >> (2nd parameter of NSRunAlertPanel) is never supposed to be a format >> string: in other words, if it happens to be, it's a non-wanted buggy >> behavior. So, if I understand your suggestion correctly, is your advice >> just a safe precaution in case there's a bug in my code? In fact I >> checked the Apple documentation and both A. Hillegaas' book "Cocoa >> Programming for Mac OS X" and "Cocoa Programming" by >> Anguish/Buck/Yacktman but I was unable to find an official >> recommendation to do so. > >So barring the possibility of bugs, alertMsg will never contain a % >character? Even something like "23% done" will cause strange behavior as >the format string parser picks up "% d" and tries to replace it with an >integer from the nonexistent argument list. > >Anyway, specifying @"%@" and then putting your string in the argument list >is always safer in this kind of situation. Even if you're completely sure >that there will never be any format string characters, that could change >after you forgot about this bit of code. > >My suggestion wasn't based on the expectation that you're doing something >wrong here, it's just the only possibility I could see. >.
I implemented your suggestions but the problem is still there. I think there are problems with run loops. Basically, I have 3 timers: a main timer, a warning timer (firing some X seconds before the main timer, and a countdown timer updating a text field every second. The main and the warning timer may open alerts with NSRunAlertPanel. The alert is open inside the fire method, so I add the timers to the NSModalPanelRunLoopMode too. This is my current code: - (void)startTimer { // ..... t = [[NSTimer alloc] initWithFireDate:fireDate interval:repeatSecs target:self selector:@selector(doGestures:) userInfo:userInfo repeats:repeatFlag]; currRunLoop = [NSRunLoop currentRunLoop]; [currRunLoop addTimer:t forMode:NSDefaultRunLoopMode]; [currRunLoop addTimer:t forMode:NSModalPanelRunLoopMode]; t2 = [[NSTimer alloc] initWithFireDate:warnFireDate interval:repeatSecs target:self selector:@selector(doGestures:) userInfo:userInfo2 repeats:repeatFlag]; [currRunLoop addTimer:t2 forMode:NSDefaultRunLoopMode]; [currRunLoop addTimer:t2 forMode:NSModalPanelRunLoopMode]; ut = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(updCountdown:) userInfo:userInfo3 repeats:YES]; [currRunLoop addTimer:ut forMode:NSModalPanelRunLoopMode]; // .... }
- (void)doGestures:(NSTimer *)aTimer { // construct alertMsg and alertMsg2 // ... if (isWarning) { NSRunAlertPanel(alertTitle2, @"%@", @"Ok", nil, nil, alertMsg2); if (isLastRepetition) { [t2 invalidate]; [t2 release]; t2 = nil; } } else { NSRunAlertPanel(alertTitle, @"%@", @"Ok", nil, nil, alertMsg); if (isLastRepetition) { [t invalidate]; [t release]; t = nil; [ut invalidate]; [ut release]; ut = nil; } } // .... }
Does anybody see anything wrong with this code?
As mentioned in previous msgs, the alert sometimes doesn't get closed although the app seems to exit from the modal loop, since I am able to use the app normally as the alert was closed. Any insight would be really appreciated. The only thing I can think of is make my own alert window and take care of closing it, but I don't understand why the above code sometimes fails. --Ettore
|
|
 | | From: | Michael Ash | | Subject: | Re: modal panel (NSRunAlertPanel) doesn't get closed | | Date: | Wed, 12 Jan 2005 12:28:42 -0600 |
|
|
 | e wrote: > > I implemented your suggestions but the problem is still there. I think > there are problems with run loops. Basically, I have 3 timers: a main > timer, a warning timer (firing some X seconds before the main timer, and a > countdown timer updating a text field every second. The main and the > warning timer may open alerts with NSRunAlertPanel. The alert is open > inside the fire method, so I add the timers to the NSModalPanelRunLoopMode > too. This is my current code: [snip]
You're adding doGestures: to the modal runloop mode, and it looks like it will fire while NSRunAlertPanel is waiting for a response. When it fires, it calls NSRunAlertPanel. This is a bad combination. NSRunAlertPanel is probably not reentrant, and the fact that you're calling it while it's already waiting for a response is probably the reason for your problems.
|
|
 | | From: | e | | Subject: | Re: modal panel (NSRunAlertPanel) doesn't get closed | | Date: | Sat, 15 Jan 2005 07:12:44 GMT |
|
|
 | On 2005-01-12 10:28:42 -0800, Michael Ash said:
> e wrote: >> >> I implemented your suggestions but the problem is still there. I think >> there are problems with run loops. Basically, I have 3 timers: a main >> timer, a warning timer (firing some X seconds before the main timer, and a >> countdown timer updating a text field every second. The main and the >> warning timer may open alerts with NSRunAlertPanel. The alert is open >> inside the fire method, so I add the timers to the NSModalPanelRunLoopMode >> too. This is my current code: > [snip] > > You're adding doGestures: to the modal runloop mode, and it looks like > it will fire while NSRunAlertPanel is waiting for a response. When it > fires, it calls NSRunAlertPanel. This is a bad combination. > NSRunAlertPanel is probably not reentrant, and the fact that you're > calling it while it's already waiting for a response is probably the > reason for your problems.
originally I was not adding the timers to the modal run loop; then I did so after reading some cocoa boards, for instance:
http://lists.apple.com/archives/cocoa-dev/2005/Jan/msg00370.html http://lists.apple.com/archives/cocoa-dev/2005/Jan/msg00376.html
After adding the timers to the modal run loop it's much harder to replicate the bug, and it happened to me only twice (after many many tests).
I am not aware if NSRunAlertPanel is reentrant or not, but the docs don't mention it. If it is not reentrant, of course weird behaviors can happen. Why do you say it's "probably" not reentrant? I could rewrite NSRunAlertPanel making sure everything is reentrant, but I fail to understand what I am doing wrong.
Anyway, when a modal panel is open and NSRunAlertPanel is called again, what happens is that another panel simply opens. Then I am usually able to close all of them. Why is this a bad combination? Do you have a specific example or pointer to the documentation that suggests that?
Any other insights? Thank you again.
|
|
 | | From: | e | | Subject: | Re: modal panel (NSRunAlertPanel) doesn't get closed | | Date: | Sat, 15 Jan 2005 02:37:11 GMT |
|
|
 | >e wrote: >> >> there are problems with run loops. Basically, I have 3 timers: a main >> timer, a warning timer (firing some X seconds before the main timer, and a >> countdown timer updating a text field every second. The main and the >> warning timer may open alerts with NSRunAlertPanel. The alert is open >> inside the fire method, so I add the timers to the NSModalPanelRunLoopMode >> too. >[snip] > >You're adding doGestures: to the modal runloop mode, and it looks like it >will fire while NSRunAlertPanel is waiting for a response. When it fires, >it calls NSRunAlertPanel. This is a bad combination. NSRunAlertPanel is >probably not reentrant, and the fact that you're calling it while it's >already waiting for a response is probably the reason for your problems.
originally I was not adding the timers to the modal run loop; then I did so after reading some cocoa boards, for instance: http://lists.apple.com/archives/cocoa-dev/2005/Jan/msg00370.html http://lists.apple.com/archives/cocoa-dev/2005/Jan/msg00376.html
After adding the timers to the modal run loop it's much harder to replicate the bug, and it happened to me only twice (after many many tests). I am not aware if NSRunAlertPanel is reentrant or not, but the docs don't mention it. If it is not reentrant, of course weird behaviors can happen. Why do you say it is "probably" not reentrant? I could rewrite NSRunAlertPanel making sure everything is reentrant, but I fail to understand what I am doing wrong. Anyway, when a modal panel is open and NSRunAlertPanel is called again, what happens is that another panel simply opens. Then I am usually able to close all of them. Why is this a bad combination? Do you have a specific example or pointer to the documentation that suggests that? Any other insights? Thank you again.
|
|
 | | From: | Michael Ash | | Subject: | Re: modal panel (NSRunAlertPanel) doesn't get closed | | Date: | Sat, 15 Jan 2005 03:00:43 -0600 |
|
|
 | e wrote: > > I am not aware if NSRunAlertPanel is reentrant or not, but the docs > don't mention it. If it is not reentrant, of course weird behaviors can > happen. Why do you say it is "probably" not reentrant?
Because it's not mentioned on Apple's page on thread-safety as being reentrant:
http://developer.apple.com/documentation/Cocoa/Conceptual/Multithreading/articles/CocoaSafety.html
Also, the documentation explicitly states that it reuses its panel rather than creating a new one each time. If that is always the case, then it will be using a panel that's already in use when you re-enter it, and I can't imagine it being good. I say "probably" because nothing explicitly says it's *not* reentrant, but that doesn't mean much.
> I could rewrite > NSRunAlertPanel making sure everything is reentrant, but I fail to understand > what I am doing wrong. > Anyway, when a modal panel is open and NSRunAlertPanel is called again, > what happens is that another panel simply opens. Then I am usually able > to close all of them. Why is this a bad combination? Do you have a > specific example or pointer to the documentation that suggests that? > Any other insights? Thank you again.
Nothing more than the above. It's just a guess.
|
|
|