Re: Bug in NSArrayController? (immutable instead of mutable dictionaries)
Re: Bug in NSArrayController? (immutable instead of mutable dictionaries)
- Subject: Re: Bug in NSArrayController? (immutable instead of mutable dictionaries)
- From: Uli Zappe <email@hidden>
- Date: Sat, 23 Oct 2004 02:03:58 +0200
Am 22.10.2004 um 22:54 schrieb Scott Anguish:
On Oct 22, 2004, at 9:22 AM, Uli Zappe wrote:
2. add a respective example to "Binding Your Preferences in Cocoa",
which should also point out that it is crucial for this to work at
all that you *must* check the "Handles Content as Compound Value"
option in the NSArrayController's Bindings Info - something I never
would have guessed from the description of this option in the docs
3. provide a factory value transformer that transforms immutable
arrays of immutable objects to mutable arrays of mutable objects
(yes, that's not hard to do yourself, but it shouldn't be necessary
to do again and again given that this is a standard situation -
actually, the very reason that such a transformer does not exist in
Cocoa made me believe for quite some hours that this just can't be
necessary for my implementation to work since it's such a standard
task I'm implementing.)
Yes. However, this isn't anywhere near as straight-forward as it seems.
Well, it didn't seem straight-forward to me ;-) , but now that I got it
working I didn't encounter any malfunctioning so far in my tests.
Nor does it really solve the problem.
Depends on what you think the problem is. You are much deeper into
Bindings than I am, but right now, I cannot see what isn't solved the
way I do it.
For handling compound preferences values like this, you're much better
off isolating that editing in it's own NSArrayController that uses an
intermediate mutable collection. That is, when you enter that 'editing
state', get the entire array from NSUserDefaultsController, make a
deep mutable copy, and use that with the new NSArrayController. when
you leave that editing state (say, switch to another prefs pane) you
then set the user defaults with that array.
Hm, it's hard for me to see the crucial difference between the above
and what's happening in my implementation.
Let's say I check a checkbox in my GUI that's bound to my
NSArrayController. As far as I have understood it, the following is
happening:
1. Via KVC, the value of the respective key in the NSMutableDicitonary
that is currently the selected one in its content array of
NSArrayController is modified.
2. Via KVC, NSArrayController modifies the content of
NSUserDefaultsController (which it is bound to). Obviously because of
the "Handles Content as Compound Value" setting, the complete content
array is sent to NSUserDefaultsController via my custom
ImmutableToMutableArrayOfObjectsTransformer.
ImmutableToMutableArrayOfObjectsTransformer's
-reverseTransformedValue:(id)value method simply returns value, thus
the array arrives unmodified at NSUserDefaultsController.
3. In turn, NSUserDefaultsController immediately notifies
NSArrayController via KVO that the user defaults have changed. (I have
a hard time understanding why this is necessary/unavoidable - I mean,
why notify the originator of a change of this very change? The answer
is probably that, as you said below, KVC is a one-way operation and
NSUserDefaultsController does not know that it was NSArrayController
that sent the modification to it.) NSArrayController requests the array
and an immutable version of the complete array is sent to it.
ImmutableToMutableArrayOfObjectsTransformer makes a deep mutable copy
of that array that arrives at NSArrayController and replaces the
original content array which with it is identical.
The result of these 3 steps:
a) the new checkbox state is stored in NSArrayController's selected
mutable dictionary
b) the new checkbox state is stored in the user preferences
Now, where in the above 3 steps do you think a problem remains? I
cannot see it. (Maybe I should add that all the preference values I
deal with do not influence the GUI, i.e. no control views in my app are
observers of my user defaults. The user default settings are just
relevant for my model objects that query NSUserDefaults if they need to
know a specific value.)
I was sceptical at the beginning if it is possible at all to bind
several controllers together, but Apple's "What Are Cocoa Bindings?"
clearly says it is, and I can't see how my implementation differs much
from the example in figure 13 of that document.
Editing arrays directly from NSUserDefaultsController has all sorts of
issues. If you're saving immediately, you have issues with null values
getting in there,
I don't understand that, nor have I experienced it in my test
(appliesImmediately, which I think you refer to, is YES in my
NSUserDefaultsController). Where should null values come from?
Also, why do you say I edit my array "directly from
NSUserDefaultsController"? From my understanding, that's exactly what I
don't do. I edit the array in NSArrayController, which *after the
change* propagates this change to NSUserDefaultsController via KVC.
if you provide temporary values to avoid that you have data that may
not be appropriate being KVO'd throughout the application.
Whatever this means exactly, it probably doesn't apply to my app,
because as I said, I have not control views as observers in my app
(i.e. the only two observers are NSArrayController and
NSUserDefaultsController).
The value transformer idea is a good one, but doesn't work very well
from my experience.
Hm, so far it just works for me. What could be problematic?
you have to use Handles as Compound Value,
I have to admit I still have no idea what this option really means and
why it is needed (I just found I have to check it for the whole
implementation to work).
which means that you have selection issues that come up.
What issues could that possibly be? That after a change in user
defaults another dictionary in NSArrayController's content array is
selected than before? I couldn't test that thoroughly so far.
The NSUserDefaultsController doesn't know that the NSArrayController
that it is sending data back to (via KVO) expects mutability. There
isn't a mechanism for that, KVO is a one way message. So, while it's
true that it appears that it is two way, they are in fact to entirely
separate processes. KVC to set, KVO returns the new value.
Yep, I know, but I still think it's a shame this can't be handled more
intelligently.
Honestly, I'm surprised to see how complicated Bindings can become as
soon as you have something a bit more advanced in its structure. As I
said before, I think handling user preferences are a prime example for
the usefulness of Bindings, and still, if they become a little bit more
advanced than the very basic case that is dealt with in "Binding Your
Preferences in Cocoa", it becomes so problematic immediately. Which is
why I think that "Binding Your Preferences in Cocoa" really should be
enhanced by additional examples and canonic implementations for cases
like the one above.
Bye
Uli
________________________________________________________
Uli Zappe, Solmsstraße 5, D-65189 Wiesbaden, Germany
http://www.ritual.org
Fon: +49-700-ULIZAPPE
Fax: +49-700-ZAPPEFAX
________________________________________________________
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Cocoa-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden