Re: Implementing NSOutlineView autosaveExpandedItems with CoreData
Re: Implementing NSOutlineView autosaveExpandedItems with CoreData
- Subject: Re: Implementing NSOutlineView autosaveExpandedItems with CoreData
- From: Ian <email@hidden>
- Date: Tue, 1 Jul 2008 07:30:35 +0100
On 1 Jul 2008, at 04:41, Andy Kim wrote:
Hi Ian,
I've got a CoreData object graph with an outline view showing
instances of an NSManagedObject subclass called "Group".
The Group class has the standard to-one relation 'parent' and to-
many 'children'.
The outline view is working perfectly.
I've set autosaveExpandedItems to YES and when I expand or unexpand
(contract?) a group my outline view's data source gets sent the
persistentObjectForItem message.
Collapse is the word used in the docs.
I can see in the prefs plist for my app that the expanded Group
itmes are being saved, and when my application launches, the
outline view's data source object gets sent the
itemForPersistentObject message.
Below is what I'm doing for each of these messages:
- (id)outlineView:(NSOutlineView*)outlineView
persistentObjectForItem:(id)item
{
NSNumber *uid=[[item representedObject] valueForKeyPath:@"uid"];
id archivedObject=[NSKeyedArchiver archivedDataWithRootObject:uid];
return archivedObject;
}
- (id)outlineView:(NSOutlineView *)outlineView
itemForPersistentObject:(id)object
{
NSNumber *uid=[NSKeyedUnarchiver unarchiveObjectWithData:object];
NSManagedObjectContext *context=[self managedObjectContext];
NSFetchRequest *request=[[NSFetchRequest alloc] init];
NSEntityDescription *groupEntityDescription=[NSEntityDescription
entityForName:@"Group" inManagedObjectContext:context];
[request setEntity:groupEntityDescription];
NSPredicate *predicate=[NSPredicate predicateWithFormat:@"uid==
%@",uid];
[request setPredicate:predicate];
NSError *error;
NSArray *fetchResults=[context executeFetchRequest:request
error:&error];
if ([fetchResults count])
return [fetchResults objectAtIndex:0];
return nil;
}
The request object is not being released.
Thanks - that one slipped my notice.
The persistentObjectForItem method successfully archives and
returns the 'uid' property for the item's represented object - this
is a unique identifier for each of my Groups.
The itemForPersistentObject successfully reconstitutes the archived
uid and correctly finds the Group with the unique 'uid' property
and returns it.
Expanded items in the outline view are not being restored however.
Is itemForPersistentObject expecting me to return something else?
My guess would be that it was expecting an instance of NSTreeNode,
since this is what I first got as 'item' in persistentObjectForItem.
Sadly though, I can't see a way to get an NSTreeNode from an object.
I have [item representedObject] for archival, but not [object
representingItem], if you see what I mean.
Obviously I've tried returning an the 'item' archived but it
doesn't respond to archiving.
Neither (obviously) does my NSManagedObject subclass... should I
implement archiving in my subclass to get this to work?
Does anyone have any clue they can distribute my way? (citation: http://www.bofhcam.org/co-larters/distributing-clue/index.html)
I've seen lots in the usual places (lists.apple.com,
cocoabuilder.com et al) about this but no actual solutions shout
out at me. Perhaps I'm not looking hard enough. (most likely).
Many TIA
Ian
I have this working in my app and I'm doing almost exactly the same
thing. I'm also using the UID as the persistent object so you don't
have to return an archived version of your whole model object or the
tree node.
I would check two things:
1. Are you setting the autosaveName to the outline view?
Yeah - I can se it in my app's prefs plist.
2. Maybe the outline view is trying to restore the expanded state
before your tree controller has content? You said
itemForPersistentObject returns the correct Group, but this actually
happened to me before, so just making sure :)
No, it's fine:
(gdb) po fetchResults
<_PFArray 0x711bb90>(
<Group: 0x711b970> (entity: Group; id: 0x1dd560 <x-coredata://E2399F1B-1569-4CF8-9C8A-1C174E6D65AE/Group/p1
> ; data: <fault>)
)
Beyond those two, if you still can't figure out why it's not
working, saving and restoring expanded state of an outline view is a
trivial task. I use the following bit of code in an NSOutlineView
subclass to do just that:
- (id)expandedState
{
NSMutableArray *state = [NSMutableArray array];
NSInteger count = [self numberOfRows];
for (NSInteger row = 0; row < count; row++) {
id item = [self itemAtRow:row];
if ([self isItemExpanded:item])
[state addObject:[[self dataSource] outlineView:self
persistentObjectForItem:item]];
}
return state;
}
- (void)setExpandedState:(id)state
{
if ([state isKindOfClass:[NSArray class]] == NO) return;
// Collapse everything first
[self collapseItem:nil collapseChildren:YES];
for (id pobj in state) {
[self expandItem:[[self dataSource] outlineView:self
itemForPersistentObject:pobj]];
}
}
You can use those two methods to save the expanded state to the user
defaults and then restore later on exactly when you need to.
- Andy Kim
Thanks - I've seen solutions like this before, I just wanted to get it
working the regular way!
Is itemForPersistentObject expecting an NSTreeNode? You say you have
it working in a similar way - what does your itemForPersistentObject
method return?
Many thanks
Ian
_______________________________________________
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