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 (Cocoa-dev@lists.apple.com)

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:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to