Maintaining mutable values with NSDictionaryControllerKeyValuePair
-
I'm using an NSDictionaryController object to control the data
provided to an NSTableView object. I'm attempting to use key-value
coding through the dictionary controller to manipulate the data in a
bindings-compatible way, by calling the method -arrangedObjects on the
NSDictionaryController, and then manipulating the
NSDictionaryControllerKeyValuePairs that this method returns in an
array.
The problem is that my values for the objects that -arrangedObjects
returns also need to be mutable dictionaries themselves. That is, my
NSDictionaryControllerKeyValuePairs look like this:
key: someKey
value: NSMutableDictionary
key: someKey1 value: someString1
key: someKey2 value: someString2
If I attempt to set the values within the NSMutableDictionary directly
via key-value coding on a completely new object, by calling -
setValue:forKeyPath:@"value.someKey1", I get errors saying that this
class isn't KVC compliant for the key someKey1 (presumably because the
KeyValuePair doesn't automatically know that I want to create an
NSMutableDictionary as the value).
So I'm left with manually creating the NSMutableDictionary value
(which is fine), and then calling setValue: on the KeyValuePair. The
problem is, even if I use an NSMutableDictionary as the value, the
KeyValuePair seems to set it with an immutable value instead
(NSDictionary, rather than NSMutableDictionary). I can see this
because if I then call setValue:forKeyPath:@"value.someKey1", I get an
error saying I'm sending a mutable method to an immutable object. But
I'm stuck, because I can't later set an entirely different
NSMutableDictionary value to the KeyValuePair if I have my table
observing someString1 or someString2, because that violates KVO.
How do I get around this problem? Is there a way to tell
NSDictionaryControllerKeyValuePair to preserve the mutability of the
values that I'm setting? It seems that it might have internal copy
semantics when setting the value rather than retain semantics, which
would cause the problems I'm seeing.
I hope that all made sense. Any help would be greatly appreciated.
Thanks!
-- Simone Manganelli -
> I'm using an NSDictionaryController object to control the data
> provided to an NSTableView object. I'm attempting to use key-value
> coding through the dictionary controller to manipulate the data in a
> bindings-compatible way, by calling the method -arrangedObjects on
> the NSDictionaryController, and then manipulating the
> NSDictionaryControllerKeyValuePairs that this method returns in an
> array.
Any luck?
I am having a similar problem - mutable dictionary objects that are
themselves stored in a dictionary will be presented as immutable
dictionaries by the NSDictionaryController. This makes it impossible
to bind controls to keypaths that drill into dictionaries below the
level of the outermost container.
i.e. even if arrangedObjects.value should point to a mutable
dictionary, attempts to edit arrangedObjects.value.someKey via a UI
control will generate the following error:
*** -[NSCFDictionary setObject:forKey:]: mutating method sent to
immutable object
Having a workaround for this would be really nice - has anyone found
one? I will file a bug as I don't think this is the behavior most
would expect.
This is turning something that would have "just worked" in about
fifteen minutes into yet another quest for a messy workaround...
Thanks in advance,
Rick -
Rick --
I pulled my hair out over this one, but I finally found an acceptable
workaround, although it doesn't solve the fundamental problem of
NSDictionaryController.
What I ended up doing is setting the whole outer dictionary (the one
controlled by the NSDictionaryController) via a KVO-compliant method.
This sucks because it means that you'll have to manually write methods
for the actions of your UI controls instead of relying on bindings to
do it for you. But it *does* get around the paradox of either being
unable to set properties of an individual object in the dictionary or
violating KVO-compliance.
So, for example, in my project, my NSDictionaryController is bound to
the entriesDict of the selected EPWeblog object in my master-detail
interface. When I want to change one of the objects in the
dictionary, I do the following:
NSMutableDictionary *tempMutDict = [NSMutableDictionary
dictionaryWithDictionary:[weblog entriesDict]];
[tempMutDict setObject:dictionaryValue forKey:theExistingKey];
[weblog setEntriesDict:tempMutDict];
entriesDict is a property of the EPWeblog object (the variable
'weblog'), and it's KVO-compliant via the entriesDict and
setEntriesDict: methods. So I simply copy the outer dictionary,
change the one object in the dictionary (represented by the new
dictionaryValue variable), and then set the outer dictionary via the
setEntriesDict: method. If you call addObject: to your
NSDictionaryController, it does precisely the same thing -- it adds a
new object and sets the whole outer dictionary via the appropriate KVO-
compliant method.
After all this, I too am planning to file a bug on
NSDictionaryController because this is pretty ridiculous for something
that should be straightforward. I did a bunch of subclassing to
figure out exactly what NSDictionaryController was doing. Even if the
dictionary it's controlling contains mutable values inside its
objects, NSDictionaryController represents them as immutable objects.
It's infuriating.
It does make me feel better that someone else is having this same
problem, though. :)
-- Simone
Il giorno 2009-01-06, alle ore 14:06, Rick Hoge ha scritto:>
>> I'm using an NSDictionaryController object to control the data
>> provided to an NSTableView object. I'm attempting to use key-value
>> coding through the dictionary controller to manipulate the data in
>> a bindings-compatible way, by calling the method -arrangedObjects
>> on the NSDictionaryController, and then manipulating the
>> NSDictionaryControllerKeyValuePairs that this method returns in an
>> array.
>
> Any luck?
>
> I am having a similar problem - mutable dictionary objects that are
> themselves stored in a dictionary will be presented as immutable
> dictionaries by the NSDictionaryController. This makes it
> impossible to bind controls to keypaths that drill into dictionaries
> below the level of the outermost container.
>
> i.e. even if arrangedObjects.value should point to a mutable
> dictionary, attempts to edit arrangedObjects.value.someKey via a UI
> control will generate the following error:
>
> *** -[NSCFDictionary setObject:forKey:]: mutating method sent to
> immutable object
>
> Having a workaround for this would be really nice - has anyone found
> one? I will file a bug as I don't think this is the behavior most
> would expect.
>
> This is turning something that would have "just worked" in about
> fifteen minutes into yet another quest for a messy workaround...
>
> Thanks in advance,
>
> Rick -
> I pulled my hair out over this one, but I finally found an
> acceptable workaround, although it doesn't solve the fundamental
> problem of NSDictionaryController.
Thanks very much for the reply and workaround. I will explore this
solution further.
The NSDictionaryController/bindings route seems to work fine if you
have a simple mutable dictionary in which the keys are strings and the
values are discrete objects like NSStrings or NSNumbers. Then you can
edit the values with no problem. It just seems to get difficult when
the dictionary values are themselves collections. I could live with
this I suppose, in cases where read-only display of the dictionary was
the primary goal. However it would really be nice to be able to edit
the contents of collections, and the present limitations should really
be mentioned in the documentation (maybe the current docs say so in
some obtuse way, but if so I didn't catch it).
Thanks again,
Rick -
>> I pulled my hair out over this one, but I finally found an
>> acceptable workaround, although it doesn't solve the fundamental
>> problem of NSDictionaryController.
>
> Thanks very much for the reply and workaround. I will explore this
> solution further.
>
> The NSDictionaryController/bindings route seems to work fine if you
> have a simple mutable dictionary in which the keys are strings and
> the values are discrete objects like NSStrings or NSNumbers. Then
> you can edit the values with no problem. It just seems to get
> difficult when the dictionary values are themselves collections. I
> could live with this I suppose, in cases where read-only display of
> the dictionary was the primary goal. However it would really be
> nice to be able to edit the contents of collections, and the present
> limitations should really be mentioned in the documentation (maybe
> the current docs say so in some obtuse way, but if so I didn't catch
> it).
>
After considering this problem some more, it seems like in my case the
easiest workaround is to abandon the idea of having a dictionary of
dictionaries and instead use an NSArray (or NSSet) of dictionaries.
This will avoid the use of mysterious immutable proxy dictionaries by
NSDictionaryController and should deliver equivalent functionality.
Originally I was attracted by the simplicity of obtaining a list of
entries using allKeys, and addressing the entries by name, but similar
functionality could be obtained with other connection objects using
predicates (with a bit more complexity).
Would still be sweet if NSDictionaryController provided deeper read-
write access to embedded dictionaries, but I won't hold my breath.
Thanks again,
Rick


