The solution I have come up with (but don't particularly like). Replace outlineView:objectValueForTableColumn:byItem: with the following code.
-(NSView*)outlineView:(NSOutlineView *)outlineView viewForTableColumn:(NSTableColumn *)tableColumn item:(id)item {
NSTableCellView *cell = [outlineView makeViewWithIdentifier:@"characterColumn" owner:self];
if([item isKindOfClass:[Character class]]) {
[cell.textField setStringValue:[item name]];
} else if([item isKindOfClass:[NSString class]]) {
[cell.textField setStringValue:item];
}
return cell;
}
Basically what this does is exactly what I'd expect the cell code to do, but it appears to retain things properly. Any insight from the masses?
EDIT: Here's the deal. NSOutlineView's dataSource delegate methods are a little bit more particular about ownership. It's not something that you have to deal with usually with a vanilla NSTableView, since there are not multiple levels of item. Basically, you need to create all of the objects for display elsewhere and make sure they are managed in memory elsewhere, because NSOutlineViewDataSource isn't going to do any of that for you.