Unobserved Changes
-
Hi everyone,
I have a Container object that has a Characteristics object which, in turn,
has a NSMutableArray ("myarray") object. I also have a ContainerController
object that I want to set up to observe changes to the NSMutableArray
object. In the ContainerController, I have a line of code:
[container addObserver: self forKeyPath: @"characteristics.myarray" options:
0 context: NULL];
I have a NSArrayController object set up to manage changes by a user to the
NSMutableArray object through a table view. I also have a button that, when
clicked, adds a row to the table. Such a change to the array does not seem
to be sending a "changed" message to the observer (the ContainerController
object). I am pretty sure that I've followed the KVO criteria regarding this
array object. How should I set this up so that my ContainerController object
will be notified when an element is added to the array?
Thanks,
Jason -
Post some code. How is clicking the button adding to the array?
Mike.
On 22 Feb 2008, at 09:45, Jason Barker wrote:
> Hi everyone,
> I have a Container object that has a Characteristics object which,
> in turn,
> has a NSMutableArray ("myarray") object. I also have a
> ContainerController
> object that I want to set up to observe changes to the NSMutableArray
> object. In the ContainerController, I have a line of code:
>
> [container addObserver: self forKeyPath: @"characteristics.myarray"
> options:
> 0 context: NULL];
>
> I have a NSArrayController object set up to manage changes by a user
> to the
> NSMutableArray object through a table view. I also have a button
> that, when
> clicked, adds a row to the table. Such a change to the array does
> not seem
> to be sending a "changed" message to the observer (the
> ContainerController
> object). I am pretty sure that I've followed the KVO criteria
> regarding this
> array object. How should I set this up so that my
> ContainerController object
> will be notified when an element is added to the array?
>
>
> Thanks,
> Jason
-
on 2/22/08 2:45 AM, <misterbarker...> purportedly said:
> [container addObserver: self forKeyPath: @"characteristics.myarray" options:
> 0 context: NULL];
AFAIK, you can't observe changes to the *contents* of an array using the
above; you can only observe when the array object itself is replaced. If,
however, you observe the arrangedObjects property of the array controller,
you will get notified when objects are added or removed.
> I have a NSArrayController object set up to manage changes by a user to the
> NSMutableArray object through a table view. I also have a button that, when
> clicked, adds a row to the table. Such a change to the array does not seem
> to be sending a "changed" message to the observer (the ContainerController
> object). I am pretty sure that I've followed the KVO criteria regarding this
> array object. How should I set this up so that my ContainerController object
> will be notified when an element is added to the array?
You may have followed KVO, but did you follow KVC, and hence have indexed
accessors? If so, then you can trap additional and deletions, and even
replacements if you implemented the optional accessor.
Best,
Keary Suska
Esoteritech, Inc.
"Demystifying technology for your home or business" -
Keary,
You guessed it. I changed the observer to the arrangedObjects property of
the array controller and now I'm getting notified of changes.
Thanks!
Jason
On Fri, Feb 22, 2008 at 11:24 AM, Keary Suska <hierophant...> wrote:
> on 2/22/08 2:45 AM, <misterbarker...> purportedly said:
>
>> [container addObserver: self forKeyPath: @"characteristics.myarray"
> options:
>> 0 context: NULL];
>
> AFAIK, you can't observe changes to the *contents* of an array using the
> above; you can only observe when the array object itself is replaced. If,
> however, you observe the arrangedObjects property of the array controller,
> you will get notified when objects are added or removed.
>
>> I have a NSArrayController object set up to manage changes by a user to
> the
>> NSMutableArray object through a table view. I also have a button that,
> when
>> clicked, adds a row to the table. Such a change to the array does not
> seem
>> to be sending a "changed" message to the observer (the
> ContainerController
>> object). I am pretty sure that I've followed the KVO criteria regarding
> this
>> array object. How should I set this up so that my ContainerController
> object
>> will be notified when an element is added to the array?
>
> You may have followed KVO, but did you follow KVC, and hence have indexed
> accessors? If so, then you can trap additional and deletions, and even
> replacements if you implemented the optional accessor.
>
> Best,
>
> Keary Suska
> Esoteritech, Inc.
> "Demystifying technology for your home or business"
>
-
On Feb 22, 2008, at 10:24 AM, Keary Suska wrote:
> on 2/22/08 2:45 AM, <misterbarker...> purportedly said:
>
>> [container addObserver: self forKeyPath: @"characteristics.myarray"
>> options:
>> 0 context: NULL];
>
> AFAIK, you can't observe changes to the *contents* of an array using
> the
> above; you can only observe when the array object itself is
> replaced. If,
> however, you observe the arrangedObjects property of the array
> controller,
> you will get notified when objects are added or removed.
This is incorrect. There are a lot of misconceptions about what
observing an array property means, as well as when you should use
controller-layer versus model-layer logic.
When you observe a property -- in the general OO sense, not the
@property sense -- you get notified of all changes to that property.
That's what observing a property means.
For *attribute* property types like strings, numbers, and dates, a
change always means replacement. Attributes are typically immutable
value types.
For *relationship* property types like mutable arrays and mutable
sets, a change can mean wholesale replacement, or it can mean addition
or removal of objects. You'll be notified for *all* such changes, so
long as they are made correctly with respect to KVC and KVO (e.g. by
manipulating the proxy object returned by -mutableArrayValueForKey: or
-mutableSetValueForKey: for the property).
Note that when you observe a relationship property, you are observing
the relationship property itself, not the objects *related by* that
relationship property. If you care about changes to them, you need to
observe them separately.
In no case should you be trying to "work around" this from model-layer
code by observing a control-layer property like an array controller's
arranged objects, or by invoking controller-layer methods like an
array controller's add/remove object methods. You can observe
properties at the model level just fine, and manipulate them just
fine; if it's not working for you, it's because there's a bug in your
code. Post it and we'll help you find it.
-- Chris -
Thanks for your help.
I created a stripped down project of the scenario. It can be downloaded
from:
http://www.neuromight.com/cocoa/ContainerTest.zip
A couple of points of interest:
- The observations are created in the awakeFromNib message in the
ContainerController class.
- I have reverted to observing the NSMutableArray called
"characteristics".
- In the interface, clicking on the add button goes unnoticed by the
observer, though it adds an object to the array.
- Modifying one of the initial rows is noticed by the observer.
Thanks again for your help!
Jason
On Fri, Feb 22, 2008 at 4:56 PM, Chris Hanson <cmh...> wrote:
> On Feb 22, 2008, at 10:24 AM, Keary Suska wrote:
>
>> on 2/22/08 2:45 AM, <misterbarker...> purportedly said:
>>
>>> [container addObserver: self forKeyPath: @"characteristics.myarray"
>>> options:
>>> 0 context: NULL];
>>
>> AFAIK, you can't observe changes to the *contents* of an array using
>> the
>> above; you can only observe when the array object itself is
>> replaced. If,
>> however, you observe the arrangedObjects property of the array
>> controller,
>> you will get notified when objects are added or removed.
>
> This is incorrect. There are a lot of misconceptions about what
> observing an array property means, as well as when you should use
> controller-layer versus model-layer logic.
>
> When you observe a property -- in the general OO sense, not the
> @property sense -- you get notified of all changes to that property.
> That's what observing a property means.
>
> For *attribute* property types like strings, numbers, and dates, a
> change always means replacement. Attributes are typically immutable
> value types.
>
> For *relationship* property types like mutable arrays and mutable
> sets, a change can mean wholesale replacement, or it can mean addition
> or removal of objects. You'll be notified for *all* such changes, so
> long as they are made correctly with respect to KVC and KVO (e.g. by
> manipulating the proxy object returned by -mutableArrayValueForKey: or
> -mutableSetValueForKey: for the property).
>
> Note that when you observe a relationship property, you are observing
> the relationship property itself, not the objects *related by* that
> relationship property. If you care about changes to them, you need to
> observe them separately.
>
> In no case should you be trying to "work around" this from model-layer
> code by observing a control-layer property like an array controller's
> arranged objects, or by invoking controller-layer methods like an
> array controller's add/remove object methods. You can observe
> properties at the model level just fine, and manipulate them just
> fine; if it's not working for you, it's because there's a bug in your
> code. Post it and we'll help you find it.
>
> -- Chris
>
-
on 2/22/08 9:59 PM, <misterbarker...> purportedly said:
> Thanks for your help.
> I created a stripped down project of the scenario. It can be downloaded
> from:
> http://www.neuromight.com/cocoa/ContainerTest.zip
>
> A couple of points of interest:
> - The observations are created in the awakeFromNib message in the
> ContainerController class.
> - I have reverted to observing the NSMutableArray called
> "characteristics".
> - In the interface, clicking on the add button goes unnoticed by the
> observer, though it adds an object to the array.
> - Modifying one of the initial rows is noticed by the observer.
Chris is correct, and I should have known better. I have never observed
arrangedObjects, but I got the example from mmalc's bindings page:
<http://homepage.mac.com/mmalc/CocoaExamples/controllers.html#observingAColl
ection>. Why he chose the specific example--something that Chris says is a
no-no--I don't know, but implicitly it didn't seem like such a big deal. So
it seems to me either like being really anal, or avoiding some specific
pitfalls, or both.
Anyway, what may be a reasonable solution to your problem is to instead bind
the array controller's contentArray to the list controller (key
"characteristics"), and have your custom controller just set the list
controller content. In my tests, observation notices are properly received.
Maybe someone smarter than myself could tell you why this is the case.
Keary Suska
Esoteritech, Inc.
"Demystifying technology for your home or business"
> On Fri, Feb 22, 2008 at 4:56 PM, Chris Hanson <cmh...> wrote:
>
>> On Feb 22, 2008, at 10:24 AM, Keary Suska wrote:
>>
>>> on 2/22/08 2:45 AM, <misterbarker...> purportedly said:
>>>
>>>> [container addObserver: self forKeyPath: @"characteristics.myarray"
>>>> options:
>>>> 0 context: NULL];
>>>
>>> AFAIK, you can't observe changes to the *contents* of an array using
>>> the
>>> above; you can only observe when the array object itself is
>>> replaced. If,
>>> however, you observe the arrangedObjects property of the array
>>> controller,
>>> you will get notified when objects are added or removed.
>>
>> This is incorrect. There are a lot of misconceptions about what
>> observing an array property means, as well as when you should use
>> controller-layer versus model-layer logic.
>>
>> When you observe a property -- in the general OO sense, not the
>> @property sense -- you get notified of all changes to that property.
>> That's what observing a property means.
>>
>> For *attribute* property types like strings, numbers, and dates, a
>> change always means replacement. Attributes are typically immutable
>> value types.
>>
>> For *relationship* property types like mutable arrays and mutable
>> sets, a change can mean wholesale replacement, or it can mean addition
>> or removal of objects. You'll be notified for *all* such changes, so
>> long as they are made correctly with respect to KVC and KVO (e.g. by
>> manipulating the proxy object returned by -mutableArrayValueForKey: or
>> -mutableSetValueForKey: for the property).
>>
>> Note that when you observe a relationship property, you are observing
>> the relationship property itself, not the objects *related by* that
>> relationship property. If you care about changes to them, you need to
>> observe them separately.
>>
>> In no case should you be trying to "work around" this from model-layer
>> code by observing a control-layer property like an array controller's
>> arranged objects, or by invoking controller-layer methods like an
>> array controller's add/remove object methods. You can observe
>> properties at the model level just fine, and manipulate them just
>> fine; if it's not working for you, it's because there's a bug in your
>> code. Post it and we'll help you find it.
>>
>> -- Chris
>>
-
On Feb 23, 2008, at 10:21 AM, Keary Suska wrote:
> Chris is correct, and I should have known better. I have never> ection>. Why he chose the specific example--something that Chris
> observed
> arrangedObjects, but I got the example from mmalc's bindings page:
> <http://homepage.mac.com/mmalc/CocoaExamples/controllers.html#observingAColl
> says is a
> no-no--I don't know, but implicitly it didn't seem like such a big
> deal.
arrangedObjects != the collection.
mmalc



