Re: Binding an Array of Dictionaries
Re: Binding an Array of Dictionaries
- Subject: Re: Binding an Array of Dictionaries
- From: Keary Suska <email@hidden>
- Date: Sun, 13 Dec 2009 09:50:38 -0700
On Dec 12, 2009, at 10:35 PM, Gerriet M. Denkmann wrote:
> Well, not quite.
> As I stated in some previous post in this thread, the NSDictionaryController (bound to "currentDictionary") fills an editable NSTableView.
> And if the user edits some key or value in this NSTableView the NSDictionaryController does NOT update "currentDictionary", but replaces it with another NSDictionary.
Forgot about that. Instead, I would recommend:
0. observe NSArrayController's "selectionIndex"
1. I am assuming that the observing object owns the array that is the content for the array controller. If not, then you need a reference to the owning object, used instead of "self" below. I am calling the content array "contentArray".
2. You will only have one property: "selectedDictionary", not an instance variable, but you implement the accessors yourself (see below)
observeValueForKeyPath tells you when the selection changes:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
// if you have a specific context, you don't need to check the key name
if( object == arrayController && context == kSelectedDictionary )
{
// when the selection changes, so does the selectedDictionary property.
[self willChangeValueForKey:@"selectedDictionary"];
[self didChangeValueForKey:@"selectedDictionary"];
}
else
{
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
Implement selectedDictionary accessors:
- (NSDictionary *)selectedDictionary
{
NSArray *arrangedObjects = [ arrayController arrangedObjects ];
NSUInteger selectedIndex = [arrayController selectedIndex];
if( selectedIndex == NSNotFound ) return nil;
return [arrangedObjects objectAtIndex: selectedIndex];
}
- (void)setSelectedDictionary:(NSDictionary *)newDictionary
{
if( newDictionary != selectedDictionary )
{
// if you implemented indexed accessors, you could use the corresponding method instead
NSMutableArray *mutableProxy = [self mutableArrayValueForKey:@"contentArray"];
// shouldn't assume that the array orders are the same, so find it
NSUInteger sourceIndex = [mutableProxy indexOfObject: selectedDictionary];
[mutableProxy replaceObjectAtIndex: sourceIndex withObject: newDictionary];
}
}
Written in Mail, and untested, so caveat emptor.
> So I also have to do:
> 5. observe "currentDictionary" and if it is no longer the original value, delete the originalDictionary from the arrayController and insert the currentDictionary.
>
>
> Here is the complete class (I renamed your "currentDictionary" to "selectedDictionary"):
> (and if you find any more silly things, please point them out!)
>
>
> #import "Test_Dict_EditAppDelegate.h"
>
> static NSString *kSelectedDictionary = @"selectedDictionary";
> static NSString *kSelectedObjects = @"selectedObjects";
>
> @implementation Test_Dict_EditAppDelegate
>
> @synthesize originalDictionary;
> @synthesize selectedDictionary;
>
> - (void)arraySelectionHasChanged;
> {
> NSArray *selectedObjects = [ arrayController selectedObjects ];
> NSMutableDictionary *currentDictionary = [ selectedObjects count ] == 1 ? [ selectedObjects lastObject ] : nil;
> self.originalDictionary = currentDictionary;
> self.selectedDictionary = currentDictionary;
> }
>
>
> - (void)applicationDidFinishLaunching:(NSNotification *)aNotification
> {
> [ self addObserver: self
> forKeyPath: kSelectedDictionary
> options: 0
> context: kSelectedDictionary
> ];
>
> [ arrayController addObserver: self
> forKeyPath: kSelectedObjects
> options: 0
> context: kSelectedObjects
> ];
>
> [ self arraySelectionHasChanged ];
> }
>
> - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
> {
> if ( object == self && context == kSelectedDictionary &&
> [ keyPath isEqualToString: kSelectedDictionary ]
> )
> {
> if ( selectedDictionary != nil && selectedDictionary != originalDictionary ) // reinsert
> {
> NSArray *arrangedObjects = [ arrayController arrangedObjects ];
> NSUInteger index = [ arrangedObjects indexOfObject: originalDictionary ];
> if ( index == NSNotFound ) ... // error
>
> [ arrayController insertObject: selectedDictionary atArrangedObjectIndex: index ];
> [ arrayController removeObjectAtArrangedObjectIndex: index + 1 ];
>
> self.originalDictionary = selectedDictionary;
> };
> }
> else if ( object == arrayController && context == kSelectedObjects &&
> [ keyPath isEqualToString: kSelectedObjects ]
> )
> {
> [ self arraySelectionHasChanged ];
> }
> else
> {
> [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
> };
> }
Keary Suska
Esoteritech, Inc.
"Demystifying technology for your home or business"
_______________________________________________
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