Re: NSUndoManager retain/release of arguments - ad infinitum
Re: NSUndoManager retain/release of arguments - ad infinitum
- Subject: Re: NSUndoManager retain/release of arguments - ad infinitum
- From: John Bartleson <email@hidden>
- Date: Thu, 13 Jan 2011 00:52:56 -0800
Thank you all for your comments. Because I think this is an important
topic (and because I'm stubborn)
I'm going to continue to beat it to death.
Because there were a number of issues brought up in the comments, let
me summarize them, with my
responses in line:
** Comment 1 (Graham Cox, January 10, 2011 9:39:06 PM PST) **
"My first thought, before I go further, is that to undo a sort,
you are doing things way too
complicated. You only need to pass the sort descriptors to the
undo manager, not a copy of the data."
** Response to Comment 1 **
It appears that I didn't properly explain that the code I
included in my second post is only
executed if the dataSource method determines that no old
sortDescriptors exist for the
data array, meaning the array is initially unsorted. If both old
and new sort descriptors
exist for the data array, which means that the array has been
previously sorted, my main
tableView:sortDescriptorsDidChange: method sets up an undo with
swapped old and new descriptors
and then sorts using the new descriptors. Simple, like you said.
I didn't include this main method
in my post. I call the code in Part 1 and Part 2 of my post only
if, as Jerry Krinock pointed out
(January 10, 2011 10:35:28 PM PST), "...the objects had been
manually arranged into some arbitrary
order by the user" and there are no old sort descriptors to use
for undo. In this case, it seemed
to me that the most efficient way to recover the original
arbitrary data order was to make a
shallow copy of the entire array.
** Comment 2 (Steven Hooley, January 11, 2011 3:27:47 AM PST) **
"either : a) sort order is a property of the window, not your
model and shouldn't be undoable at
all.... OR b) the sort order is inherently part of your model,
your data is an ordered-set and the
user can arbitrarily order the items as she pleases."
** Response to Comment 2 **
Good point, and one that I hadn't thought of. I had
simplistically designed my app to use
sort order as b) part of the model, but a) suggests interesting
design possibilities.
** Comment 3 (Graham Cox, January 10, 2011 9:39:06 PM PST) **
"Specifying 'assign' here is probably wrong. It is not retaining
the assigned array, so you are
stating you don't own it. Yet I suspect that you do want to own
it. You're relying on the undo
manager retaining it because you have neglected to do so."
** Response to Comment 3 **
You're right - it's sloppy coding on my part. In my post I showed
the @property in a comment in case
someone would see if this was wrong. I changed the @property from
'assign' to 'retain', as you
suggested, and there's no crash on Redo. However, there's still a
problem in that I don't know
if the array I allocated (in Part 1) with mutableCopyWithZone: is
always being released. I'll
explain again:
The real point of my original plaintive cry, and I'm sorry if it's
become obfuscated, is that I
had to allocate memory as part of setting up for undo, but I couldn't
find any *simple* way to
keep track of whether that memory is still in use or not, thus
threatening a memory leak. This
is not a sorting problem - it appears that it will occur generically
whenever we write reference-
counted code that allocates memory and then passes that memory,
usually via -prepareWithInvocationTarget:,
to an undo method.
Graham Cox made an interesting comment earlier:
"...once the undo manager performs the undo, it will release the
invocation that is retaining
the array, which will dealloc it."
This gave me a glimmer of hope to explain what's going on. If in my
method I allocate an
object (see the Part 1 code in my 2nd post), save a pointer to the
object in the local variable
'unsortedArray', pass the pointer to -prepareWithInvocationTarget:,
then exit the method, my pointer
is gone. If I haven't kept a copy of the pointer (say in an NSDocument
instance variable)
-prepareWithInvocationTarget: (or the instance of NSUndoManager or
whatever) is now sole
owner of the pointer.
Because it owns the only pointer, -prepareWithInvocationTarget: (or
whatever) now owns the object.
Recall that, after I fixed my @property, my code appears to work
properly. Ignoring the fact that
I don't know any way to verify that the object is actually being
deallocated at NSDocument dealloc time,
I conclude that NSUndoManager and -prepareWithInvocationTarget: must
be designed to retain and
release objects passed to them as needed to provide undo
functionality. As Graham says: "it
follows the rules for ownership of objects, so by and large does the
'right thing'."
There's appears to be only one problem remaining: this behavior is not
documented anywhere I can
find. In fact, Apple's 'Undo Architecture' implies just the opposite:
"An NSUndoManager object does
not retain the targets of undo operations."
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden