Date
1 - 14 of 14
NSAlert boxes ...
Peter Hudson
Hi There
I see from the docs that when you create an NSAlert that you should dispose of it yourself. My code for creating a simple alert and using it looks like this :- NSAlert *alert = [[[NSAlert alloc] init] autorelease]; alert.messageText = @:Some message or other”; [alert addButtonWithTitle:@"Create category"]; [alert addButtonWithTitle:@"Cancel"]; NSModalResponse choice = [alert runModal]; Etc ….. Is the use of an autorelease here O.K. ? It certainly seems to work ….. Peter |
|
Sandor Szatmari
Peter,
On Feb 16, 2020, at 08:18, Peter Hudson via Groups.Io <Peter.hudson@...> wrote:
You take ownership of an object when you call -retain or -copy on an existing object, or use -new, -alloc/-init when creating an object. As far as I’m aware there are no exceptions to these ownership rules. In MRR you are responsible for calling -release/-autorelease on any object you used these methods to create/copy/take ownership. These rules are essentially true in ARC too, except the compiler figures out when to call -release so you don’t explicitly call it. Here is some additional reading on the topic.
It appears to be but I cannot tell what else you do with ‘alert’. -autorelease says that the object should live for the current scoped autorelease-pool. So, if this alert panel is not supposed to live beyond the current autorelease-pool, then the code is fine. If it does live beyond it, then you need to transfer ownership to that scope. Sandor
|
|
Peter Hudson
Thanks Sandor.
toggle quoted message
Show quoted text
My use of alert is very tightly scoped - and only used once - and not passed on. Many thanks for the link. Peter
|
|
Alex Zavatone
Why are you making it autorelease?
toggle quoted message
Show quoted text
Run your method, display and dispose of the alert and then while your app is still running click on the Memory Graph Debugger icon in the debug bar. Look at your allocations and leaks to see if any object of an NSAlert class is still there. This will tell you if it’s needed or not.
|
|
Alex Zavatone
On Feb 16, 2020, at 9:37 AM, Peter Hudson via Groups.Io <Peter.hudson@...> wrote:My expectation is that autorelease is not needed. In any case, if you do use the memory graph debugger to see if it stays allocated or not, and if autorelease is needed, please let us know. |
|
Graham Cox
Hi Peter,
toggle quoted message
Show quoted text
FWIW, I’ve always done exactly the same as this too, and have never had an issue. My understanding (which may be wrong) is that the modal loop that runs the alert temporarily retains it, so you are safe no matter whether the alert is released by you afterwards, or autoreleased. The point is, your code follows the normal rules. There’s no special case for NSAlert or other modal dialogs, because internal code behind the scenes makes sure the normal rules apply. —Graham
|
|
Alex Zavatone
On Feb 16, 2020, at 5:04 PM, Graham Cox <graham@...> wrote:Sorry, A bit groggy here. If my previous assumption that autorelease isn’t needed is incorrect, then it might be that the instance will be retained until the reference to it is cleared or the enclosing object is deallocated. In any case, it’s an easy check. |
|
Graham Cox
Normal rules require that you either autorelease it or release it when you’re done (assuming manual MM of course).
toggle quoted message
Show quoted text
If no autorelease or release was required, then that would be an exception to normal rules, and NSAlert is not documented as an exception to those rules. However, the alert can stay on screen for a long time, and the event loop is running, albeit modally. That means that autorelease pools are getting drained. So *something* must be keeping the alert alive until the user dismisses it. —Graham
|
|
Peter Hudson
Thanks Graham and Alex. I had reached the same sort of conclusions - but could not find any corroborative info anywhere .... Peter On 16 Feb 2020, at 23:59, Graham Cox <graham@...> wrote:
|
|
Sandor Szatmari
The MRR rules are straight forward and deviating from them because the runloop may retain the alert is asking for trouble in my opinion. There is no harm in taking ownership of the alert and releasing/autoreleasing it. I would argue that doing so ensures that any changes in SDK/runtime behavior don’t adversely affect your product.
toggle quoted message
Show quoted text
Sandor On Feb 16, 2020, at 19:26, Peter Hudson via Groups.Io <Peter.hudson@...> wrote:
|
|
Graham Cox
That’s exactly what I’m saying - you are taking ownership of it with alloc+init. Then you release it or autorelease it within the scope of setting it up. Normal rules. But the point is the alert is run asynchronously, so it has to survive long after the scope of where you instantiated and set it up. Long after the next autorelease drain in fact. But that is someone else's problem - the run-loop’s, I’m supposing. The alternative is to try to take ownership of it until it is finally and completely dismissed, which requires an unbalanced release in the completion block. This not only flags a warning when you compile, but it’s simply unnecessary. Trying to overthink the ownership rules in this case leads to code that is not only complicated, but redundant. The designers of NSAlert have already taken its lifetime into consideraton, so YOUR ownership of it only lasts as long as it takes to instantiate it, set it up, and ask it to run modally. Peter’s original code, where he autoreleases as part of alloc + init, works absolutely fine. —Graham |
|
Jon Gotow
You're making this far more complicated than it is (talking about running the alert asynchronously, etc).
toggle quoted message
Show quoted text
NSModalResponse choice = [alert runModal]; will run the alert synchronously. Note that it returns a result from this method call, meaning that the call blocks by running its own modal event loop in runModal and only returns after the user has clicked on a button. That means that your autorelease is fine - the scope of this alert is just within the current function, so it'll get cleaned up at the end of the current runloop invocation. That said, you can also just release it manually after you call runModal, like this: NSAlert *alert = [[NSAlert alloc] init]; alert.messageText = @"Some message or other”; [alert addButtonWithTitle:@"Create category"]; [alert addButtonWithTitle:@"Cancel"]; NSModalResponse choice = [alert runModal]; [alert release]; If you were to use [NSAlert beginSheetModalForWindow:completionHandler:], then you'd have to worry about lifecycle of the alert extending beyond the current function context. - Jon On Feb 16, 2020, at 6:17 AM, Peter Hudson via Groups.Io <Peter.hudson@...> wrote: |
|
Graham Cox
That is the case I’m talking about and no, it works fine even if you don’t “worry” about the lifecycle. Just alloc + init + autorelease, then beginSheet…. it works, it has always worked since completion blocks were introduced. It also works for the -runModal case also, you can autorelease prior to that call and that also doesn’t cause a lifecycle issue. You can certainly “worry” about extending the lifecycle into the completion block if you want, except the unbalanced release will throw a compiler warning. That in itself shows how unnecessary it is to bother with. TL;DR: Normal rules apply, stop overthinking this! Just because an NSAlert has some unusual asynchronous lifespan doesn’t mean it needs to be treated any differently from any other object you instantiate. —Graham |
|
Jon Gotow
Oh interesting - it looks like when you call [NSAlert beginSheetModalForWindow:completionHandler:], the alert gets retained by the parent window's attachedSheet property. So you're right, no issues there either. Now that you've brought it up, I have to say I've never worried about the alert being released too early in my code when I use beginSheetModalForWindow - I never gave it much thought because it just worked.
toggle quoted message
Show quoted text
- Jon On Feb 17, 2020, at 12:54 AM, Graham Cox <graham@...> wrote: |
|