• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: NSUndoManager retain/release of arguments - ad infinitum
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: NSUndoManager retain/release of arguments - ad infinitum


  • Subject: Re: NSUndoManager retain/release of arguments - ad infinitum
  • From: John Bartleson <email@hidden>
  • Date: Mon, 10 Jan 2011 20:37:55 -0800

Thanks for your replies. I'm hoping that the conclusion will help others who are confused by the existing
documentation of MM in NSUndoManager. So here's what I'm doing:


My reference-counted, document-based app uses a table view. The table view supports sorting by clicking in
the header. The app supports undo. Undoing the sort is where things got complicated. Here's the code I call when
the tableView:sortDescriptorsDidChange: dataSource method determines that no old sortDescriptors exist for
the data array, meaning the array is initially unsorted:


// **** Part 1 ****
- (void)sortUsingNewDescriptors:(NSArray *)theNewDescriptors
tableView:(NSTableView *)theTableView
{
NSMutableArray *theArrayToSort = [/*index into database*/ itemArray];
// Snapshot with a shallow copy so the user gets the original unsorted array on Undo
NSMutableArray *unsortedArray = [theArrayToSort mutableCopyWithZone:nil];
[[[self undoManager] prepareWithInvocationTarget:self] replaceArrayWithArray:unsortedArray
andDescriptors:nil
tableView:theTableView ];
[theArrayToSort sortUsingDescriptors:theNewDescriptors];
[theTableView reloadData];
}


// **** Part 2 ****
- (void)replaceArrayWithArray:(NSMutableArray *)newArray
andDescriptors:(NSArray *)newDescriptors
tableView:(NSTableView *)theTableView
{
// Save pointer to current array
NSMutableArray *currentArray = [/*index into database*/ itemArray];
NSArray *currentDescriptors = [theTableView sortDescriptors];
[[[self undoManager] prepareWithInvocationTarget:self] replaceArrayWithArray:currentArray
andDescriptors:currentDescriptors
tableView:theTableView ];
// Move pointer to new array into the data
[/*index into database*/ setItemArray:newArray]; // @property (readwrite, assign) NSMutableArray *itemArray;
signalDescriptorChange = NO; // Temporarily turn off tableView:sortDescriptorsDidChange: dataSource
[theTableView setSortDescriptors: newDescriptors]; //- method call so we don't get re-entered
signalDescriptorChange = YES;
[theTableView reloadData];
}


In Part 1, I make a shallow copy of the unsorted array for later possible use by Undo, then set up the Undo
with the prepareWithInvocationTarget: call, then finally sort the original array.


Part 2 will get called if Undo (or Redo) is selected by the user. I save pointers to the current data and its
descriptors, set up for a Redo using prepareWithInvocationTarget:, then replace the data array and its descriptors
with the ones in the previous prepareWithInvocationTarget: call.


The general effect of all this is that the unsorted and sorted data arrays are swapped as the user selects Undo and Redo.

Here's the problem: in Part 1, the mutableCopyWithZone: call allocates a new unsortedArray. In a reference-counted
environment, it (or the original theArrayToSort, depending on the user's selection of Undo/Redo) won't be released
as currently coded and there'll be an ugly memory leak.


Since I allocated unsortedArray it's my responsibility to release it. But if I release it after the prepareWithInvocationTarget:
call (in Part 1) it causes a crash on Redo. I also thought of doing a retain/release when swapping the arrays in Part 2, but
that can't be a complete solution because unsortedData will still never be released if the user never does Undo.


(As Aaron Hillegass says in his book, "Sometimes when I think about undo, my head starts to swim a bit." By the way, kudos to Aaron for
devoting a chapter to undo in his book. I can't find any other reference besides Apple's rather limited "Undo Architecture".)


As a possible solution, I can imagine writing a new class, let's call it 'UndoMemory', that maintains a pool of pointers that need
to be released when the document is deallocated. In Part 1 (above), I would call an UndoMemory method that adds
the unsortedArray pointer to the pool. In Part 2, I would call another UndoMemory method that removes newArray
from the pool and adds the currentArray pointer. At document deallocation time I would call a third method that releases
any pointers remaining in the pool.


UndoMemory would probably work but seems too complicated. I'd be writing a new layer of memory management, with potential gotchas.

Note that this isn't just a sort-specific problem. Any Undo of a memory-allocated variable (as opposed to a primitive)
in a reference-counted environment will stumble on this problem.


On Jan 9, 2011, at 10:12 PM, Graham Cox wrote:

Actually, it doesn't really matter what NSUndoManager does with arguments, all you really need to know is that it follows the rules for ownership of objects, so by and large does the 'right thing'. It does lots of wrong things, IMO, but incorrect memory management isn't among them.

_______________________________________________

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


  • Follow-Ups:
    • Re: NSUndoManager retain/release of arguments - ad infinitum
      • From: Graham Cox <email@hidden>
References: 
 >NSUndoManager retain/release of arguments - ad infinitum (From: John Bartleson <email@hidden>)
 >Re: NSUndoManager retain/release of arguments - ad infinitum (From: Graham Cox <email@hidden>)

  • Prev by Date: Re: document architecture question
  • Next by Date: Re: document architecture question
  • Previous by thread: Re: NSUndoManager retain/release of arguments - ad infinitum
  • Next by thread: Re: NSUndoManager retain/release of arguments - ad infinitum
  • Index(es):
    • Date
    • Thread