I'm writing a sandboxed ARC app with a view-based NSTableView that accepts dragged-and-dropped files (NSURL
s). I ran into some significant strangeness in the following NSTableViewDelegate
method:
- (NSView *)tableView:(NSTableView *)tv
viewForTableColumn:(NSTableColumn *)tc
row:(NSInteger)row
{
// `files' is an NSMutableArray* ivar containing NSURLs
// that have been dropped into this table
NSURL *url = [files objectAtIndex:row];
NSString *fileName = [url lastPathComponent];
NSImage *icon = [self iconForURL:url];
NSTableCellView *view = [tv makeViewWithIdentifier:[tc identifier] owner:self];
[[view textField] setStringValue:fileName];
[[view imageView] setImage:icon];
return view;
}
I can drag one file into the table view, and it displays correctly. When I drag a second file, I get this error:
*** Canceling drag because exception 'NSRangeException' (reason '*** -[__NSArrayM insertObject:atIndex:]: index 1 beyond bounds for empty array') was raised during a dragging session
Stepping through the debugger, I discovered that files
"becomes empty" -- actually becomes a new object instance -- after the call to makeViewWithIdentifier:owner:
. I assume this is some aspect of ARC that I don't understand, but it seems to me that the object has a strong reference to its own ivar (by default); how could it get released and re-created out from under me?
I have come up with two hacks to work around this:
- pass the ivar as the owner of the table cell view (hoping that in future releases it will continue to hold a strong reference); or
- create a local variable to point to the ivar's object and re-assign the ivar to the old object (this is obviously wasteful as it creates a replacement array in the meantime).
What am I missing here? These workarounds should not be necessary.