KVO and array item observation
-
I have a bid revision object that holds a to-many NSSet reference to a
group of items that constitute a tree. Some of those items are roots
and have a nil parent. In my bid revision object I've set up a
rootItems method that uses a predicate to return a filtered set of the
items with nil parents and uses keyPathsForValuesAffectingRootItems to
be aware of changes to the items set as a whole and generate
appropriate KVO notifications.
I have a problem though that when an item that's already in the set,
but not a root, becomes a root by having its' parent set to nil. This
does not cause KVO notifications to be sent out for the rootItems
property because technically the items set as a whole has not changed.
I naïvely tried to add @"items.parent" to the keyPathsForValues...
method which of course didn't work since you can't observe groups of
properties in a set or array. Right now, I'm sending a willChange/
didChange method pair after performing parent changes of subitems and
after undo/redo events and it *seems* to be working fine. This seems
grotesque though and sure to cause me problems later.
Is there any way to force a KVO update of a property besides a
willChange/didChange method pair?
Is there a better way?
Ashley -
On Oct 28, 2008, at 2:13 AM, Ashley Clark wrote:
> I have a bid revision object that holds a to-many NSSet reference to
> a group of items that constitute a tree. Some of those items are
> roots and have a nil parent. In my bid revision object I've set up a
> rootItems method that uses a predicate to return a filtered set of
> the items with nil parents and uses
> keyPathsForValuesAffectingRootItems to be aware of changes to the
> items set as a whole and generate appropriate KVO notifications.
>
> I have a problem though that when an item that's already in the set,
> but not a root, becomes a root by having its' parent set to nil.
> This does not cause KVO notifications to be sent out for the
> rootItems property because technically the items set as a whole has
> not changed.
>
> I naïvely tried to add @"items.parent" to the keyPathsForValues...
> method which of course didn't work since you can't observe groups of
> properties in a set or array. Right now, I'm sending a willChange/
> didChange method pair after performing parent changes of subitems
> and after undo/redo events and it *seems* to be working fine. This
> seems grotesque though and sure to cause me problems later.
>
> Is there any way to force a KVO update of a property besides a
> willChange/didChange method pair?
> Is there a better way?
I've re-architected my design somewhat to work around the issue I
described before and avoid issuing empty willChange/didChange pairs
but I think I'm seeing a bug (in Apple's framework?) now that I'm not
sure how to track.
My object hierarchy looks like this:
JTBidRevision maintains a set of JTBidItem objects that represent the
top items of the tree.
These JTBidItem objects in turn reference a JTInventory object.
And these JTInventory objects each reference a set of
JTInventoryDependency objects.
My JTBidItem class has a method that returns a coalesced ordered array
of objects that it displays as children, some of them are the
JTInventoryDependency objects referenced through its JTInventory
object and others are direct JTBidItem descendants of the node.
The set of dependency objects returned also depends on the state of a
variable in the parent JTBidRevision object. Depending on this
variable some dependency objects will be or will not be part of the
orderedChildren method result.
I've set up my set of keyPaths that affect the orderedChildren set and
it appears to be working in the general case in that if I change the
watched value in my JTBidRevision instance the appropriate
notifications are sent and the tree reloads correctly the first time
for all elements. If I then change that value a second time, one of my
objects has its orderedChildren method invoked twice while another of
the objects gets skipped and the display of the tree is not updated
correctly from that point on.
The JTBidItem objects that are exhibiting this behavior both maintain
a reference to the same JTInventory object.
My keyPathsForValues... method looks like this for my JTBidItem's
orderedChildren:
+ (NSSet *)keyPathsForValuesAffectingOrderedChildren {
return [NSSet setWithObjects:@"children",
@"inventoryItem.dependentInventoryItems", @"owningRevision.piping",
nil];
}
The owningRevision itself is a derived value also with this
keyPathsForValues..., the owningRevision method walks up the tree to
find the owning revision object.
+ (NSSet *)keyPathsForValuesAffectingOwningRevision {
return [NSSet setWithObjects:@"parent", @"bidRevision", nil];
}
Everything else appears to be working fine and the problem only occurs
when two or more bid item objects in my tree both reference the same
JTInventory object. Ideas?
Ashley -
I've made a test project that exhibits this behavior if anyone cares
to look and filed a bug rdar://6327051
http://idisk.mac.com/aclark78-Public/KVONotificationBug.zip
Ashley
On Oct 28, 2008, at 4:30 PM, Ashley Clark wrote:
> On Oct 28, 2008, at 2:13 AM, Ashley Clark wrote:
>
>> I have a bid revision object that holds a to-many NSSet reference
>> to a group of items that constitute a tree. Some of those items are
>> roots and have a nil parent. In my bid revision object I've set up
>> a rootItems method that uses a predicate to return a filtered set
>> of the items with nil parents and uses
>> keyPathsForValuesAffectingRootItems to be aware of changes to the
>> items set as a whole and generate appropriate KVO notifications.
>>
>> I have a problem though that when an item that's already in the
>> set, but not a root, becomes a root by having its' parent set to
>> nil. This does not cause KVO notifications to be sent out for the
>> rootItems property because technically the items set as a whole has
>> not changed.
>>
>> I naïvely tried to add @"items.parent" to the keyPathsForValues...
>> method which of course didn't work since you can't observe groups
>> of properties in a set or array. Right now, I'm sending a
>> willChange/didChange method pair after performing parent changes of
>> subitems and after undo/redo events and it *seems* to be working
>> fine. This seems grotesque though and sure to cause me problems
>> later.
>>
>> Is there any way to force a KVO update of a property besides a
>> willChange/didChange method pair?
>> Is there a better way?
>
> I've re-architected my design somewhat to work around the issue I
> described before and avoid issuing empty willChange/didChange pairs
> but I think I'm seeing a bug (in Apple's framework?) now that I'm
> not sure how to track.
>
>
> My object hierarchy looks like this:
>
> JTBidRevision maintains a set of JTBidItem objects that represent
> the top items of the tree.
> These JTBidItem objects in turn reference a JTInventory object.
> And these JTInventory objects each reference a set of
> JTInventoryDependency objects.
>
> My JTBidItem class has a method that returns a coalesced ordered
> array of objects that it displays as children, some of them are the
> JTInventoryDependency objects referenced through its JTInventory
> object and others are direct JTBidItem descendants of the node.
>
> The set of dependency objects returned also depends on the state of
> a variable in the parent JTBidRevision object. Depending on this
> variable some dependency objects will be or will not be part of the
> orderedChildren method result.
>
>
> I've set up my set of keyPaths that affect the orderedChildren set
> and it appears to be working in the general case in that if I change
> the watched value in my JTBidRevision instance the appropriate
> notifications are sent and the tree reloads correctly the first time
> for all elements. If I then change that value a second time, one of
> my objects has its orderedChildren method invoked twice while
> another of the objects gets skipped and the display of the tree is
> not updated correctly from that point on.
>
> The JTBidItem objects that are exhibiting this behavior both
> maintain a reference to the same JTInventory object.
>
>
> My keyPathsForValues... method looks like this for my JTBidItem's
> orderedChildren:
>
> + (NSSet *)keyPathsForValuesAffectingOrderedChildren {
> return [NSSet setWithObjects:@"children",
> @"inventoryItem.dependentInventoryItems", @"owningRevision.piping",
> nil];
> }
>
>
> The owningRevision itself is a derived value also with this
> keyPathsForValues..., the owningRevision method walks up the tree to
> find the owning revision object.
>
> + (NSSet *)keyPathsForValuesAffectingOwningRevision {
> return [NSSet setWithObjects:@"parent", @"bidRevision", nil];
> }
>
>
> Everything else appears to be working fine and the problem only
> occurs when two or more bid item objects in my tree both reference
> the same JTInventory object. Ideas?



