Re: Bind NSTableView to array of dictionaries in user defaults

2016-05-06 Thread Keary Suska

> On May 5, 2016, at 7:47 PM, Jerry Krinock  wrote:
> 
> After reading Quincey’s reply, I had concluded that this is one of those 
> cases where Cocoa Bindings requires additional “glue”, which defeats one of 
> the two purposes of Cocoa Bindings.  But it would be very cool if there were 
> some configuration change that would be make this work in both directions.  
> It seems like we’re really close.
> 
> I’m accustomed to doing this kind of code-less binding to a Core Data model, 
> wherein it “just works”.  That’s not surprising, because of course Core Data 
> knows the data model in great detail.  It can observe everything.

Trying out your example it looks like both you and Quincey may be correct, but 
on the opposite ends. The issue appears to be something with how view-based 
tables work, rather than NSArrayController. If you substitute with a cell-based 
table, it works flawlessly. The issue seems to involve binding through 
objectValue, so I guess you are back to needing some kind of glue code.

I was able to get it to work properly by proxy-ing the array in the app 
delegate, so this must specifically be an interaction between view-based tables 
and NSUserDefaultsController. I would file a radar, FWIW.

HTH,

Keary Suska
Esoteritech, Inc.
"Demystifying technology for your home or business"


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Bind NSTableView to array of dictionaries in user defaults

2016-05-05 Thread Jerry Krinock
Thank you, Keary. 

> On 2016 May 05, at 13:47, Keary Suska  wrote:
> 
> 
>> On May 5, 2016, at 7:44 AM, Jerry Krinock  wrote:
>> 
>> So I bound the Content Array of the array controller to the 'values' of the 
>> shared user defaults controller with an arbitrary key path, which pleasantly 
>> became the key to the array in the user defaults.  I set "Handles Content as 
>> Compound Values” to ON.
> 
> Is this a single or multi-level keypath?

single…

Bind to = Shared User Default Controller
Controller Key = values
Model Key Path = persons

Cocoa creates the “lower” levels (firstName and lastName in my demo) as 
dictionary keys automatically.

> IIRC the issues Quincy is referring to are common in a multiple-object 
> keypath, especially for defaults as NSUserDefaultsController uses some 
> internal trickery to edit the immutable collections maintained by 
> NSUserDefaults.

Yes, this is not that.

> I cannot replicate this behavior with a straightforward approach. Can you 
> create a reduction that replicates the behavior?

https://github.com/jerrykrinock/ArrayDictionaryDefaultsDemo

>> In the array controller's content, the object attribute is always changed as 
>> expected.  So, the problem is the binding of the array controller content to 
>> user defaults, and I think the explanation is that, as always, KVO is 
>> “shallow”.  Observing an array does not observe changes to its elements.
> 
> This is curious—how do you know that the attribute is being changed as 
> expected?

By stopping execution and printing the array controller’s “content” in the 
debugger.  I see the new value in the dictionary.

> Is it that it shows in the UI, but is not persisted?

Yes, when I type a new value into the table, it stays there.  But it goes back 
to the old value upon relaunch.

> Have you changed the default value of -[NSUserDefaultsController  
> appliesImmediately]?

I just tried it.  It did not help.  I had already tried -[NSUserDefaults 
synchronize] after changing the value, which I presume does the same thing 
“manually”.

* * *

After reading Quincey’s reply, I had concluded that this is one of those cases 
where Cocoa Bindings requires additional “glue”, which defeats one of the two 
purposes of Cocoa Bindings.  But it would be very cool if there were some 
configuration change that would be make this work in both directions.  It seems 
like we’re really close.

I’m accustomed to doing this kind of code-less binding to a Core Data model, 
wherein it “just works”.  That’s not surprising, because of course Core Data 
knows the data model in great detail.  It can observe everything.


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Bind NSTableView to array of dictionaries in user defaults

2016-05-05 Thread Keary Suska

> On May 5, 2016, at 7:44 AM, Jerry Krinock  wrote:
> 
> In an OS X app, I wanted to bind a table of objects, each represented by a 
> dictionary, to an array of dictionaries in user defaults.
> 
> So I bound the Content Array of the array controller to the 'values' of the 
> shared user defaults controller with an arbitrary key path, which pleasantly 
> became the key to the array in the user defaults.  I set "Handles Content as 
> Compound Values” to ON.

Is this a single or multi-level keypath? IIRC the issues Quincy is referring to 
are common in a multiple-object keypath, especially for defaults as 
NSUserDefaultsController uses some internal trickery to edit the immutable 
collections maintained by NSUserDefaults.

> Result: The table is populated as expected from user defaults when its window 
> opens, and all works and persists as expected if user adds or deletes an 
> object (row).  But changes to object attributes are persisted only for new 
> objects, and only if user adds *another* object before quitting.

I cannot replicate this behavior with a straightforward approach. Can you 
create a reduction that replicates the behavior?

> In the array controller's content, the object attribute is always changed as 
> expected.  So, the problem is the binding of the array controller content to 
> user defaults, and I think the explanation is that, as always, KVO is 
> “shallow”.  Observing an array does not observe changes to its elements.

This is curious—how do you know that the attribute is being changed as 
expected? Is it that it shows in the UI, but is not persisted? Have you changed 
the default value of -[NSUserDefaultsController  appliesImmediately]?

Keary Suska
Esoteritech, Inc.
"Demystifying technology for your home or business"


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Re: Bind NSTableView to array of dictionaries in user defaults

2016-05-05 Thread Quincey Morris
On May 5, 2016, at 06:44 , Jerry Krinock  wrote:
> 
> I’m disapointed that the “magic of Cocoa Bindings” does not seem to provide a 
> simple “code-less” solution to this simple requirement.  Did I miss something?

It’s never been possible to bind “through” a NSArray or NSSet. AFAICT, that’s 
what’s gone wrong in your scenario, the involvement of user defaults here being 
a decorative factor only.

If you think about it, it should be clear that this “defect” is the same “How 
does my object know if any of its properties has changed?” question that comes 
up from time to time. There isn’t any good, straightforward way.

You can, for example, override ‘setValue:forKey:’ in the class of the array 
elements. That will give you a single point of intervention when any of the 
element properties are changed via KVC, as happens with bindings-related 
changes from the UI. But the element doesn’t automatically know what array it 
is a member of, so you’d need ad-hoc code to propagate the change to the 
specific property of the specific object that the array represents. (That is, 
it isn’t even enough to know the array.)

In this case, the simplest solution is probably to implement a custom setter 
(if Obj-C, or a ‘didSet’ accessor if Swift) for each property of each element 
that triggers a re-save of the user defaults. Alternatively, if what is at each 
index of the array is semantically fixed, you could save each element in user 
defaults under a unique key and avoid the array. Or, you might be able to use a 
NSDictionary instead of an array, which shouldn’t exhibit this “bind-through” 
limitation, because changes to NSMutableDictionary keys are KVO compliant.)

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Bind NSTableView to array of dictionaries in user defaults

2016-05-05 Thread Jerry Krinock
In an OS X app, I wanted to bind a table of objects, each represented by a 
dictionary, to an array of dictionaries in user defaults.

So I bound the Content Array of the array controller to the 'values' of the 
shared user defaults controller with an arbitrary key path, which pleasantly 
became the key to the array in the user defaults.  I set "Handles Content as 
Compound Values” to ON.

Result: The table is populated as expected from user defaults when its window 
opens, and all works and persists as expected if user adds or deletes an object 
(row).  But changes to object attributes are persisted only for new objects, 
and only if user adds *another* object before quitting.

In the array controller's content, the object attribute is always changed as 
expected.  So, the problem is the binding of the array controller content to 
user defaults, and I think the explanation is that, as always, KVO is 
“shallow”.  Observing an array does not observe changes to its elements.

I’m disapointed that the “magic of Cocoa Bindings” does not seem to provide a 
simple “code-less” solution to this simple requirement.  Did I miss something?

Jerry

I also tried this using a custom object instead of an NSMutableDictionary as 
the content class of the array controller, making my custom class conform to 
NSCoding, and inserting a NSKeyedUnarchiveFromData value transformer into the 
binding.  Result: Exactly the same deficiency.


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com