0

I'm building an array via a block call and want to use it to populate cells of a UITableView. I'm trying to use KVO to listen to the changes to the array but I can't find a way to target it.

This is a bit dated, but it says that arrayByAddingObjectsFromArray is what I want to be using. https://github.com/sebastienwindal/iOSPatterns/wiki/Key-Value-Observing

Adding the observer:

[self.array addObserver:self forKeyPath:@"arrayData" options:NSKeyValueObservingOptionNew context:nil];

And then adding data to the array:

[array.arrayData arrayByAddingObjectsFromArray:newItems];

The observeValueForKeyPath: method is pretty simple right now and just gives a nice place to set a debugger breakpoint.

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    NSLog(@"break here");
}

Any ideas? Should I be using NSMutableArray instead?

Apologies in advance if my SO searching was bad and this was already asked 200 times. ;)

SirJay
  • 119
  • 4
  • 8

2 Answers2

0

What [array.arrayData arrayByAddingObjectsFromArray:newItems]; does is creating a new array tempArray by copying all the elements from arrayData, and then append newItems to its end.

I think what you want is to grab the new array and assign it back to the self.array by self.array = [self.array arrayByAddingObjectsFromArray:newItems];. In this case your new self.array points to a new memory address different from the one you allocated.

[self addObserver:self forKeyPath:@"array" options:NSKeyValueObservingOptionNew context:nil]; provided you have a NSArray *array property.

Together with:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { NSLog(@"break here"); }

You will be able to monitor its change for its pointer.

monkeyMoo
  • 173
  • 1
  • 1
  • 7
0

This:

[array.arrayData arrayByAddingObjectsFromArray:newItems];

actually has no effect. The -arrayByAddingObjectsFromArray: creates and returns a new array. It does not affect the receiver (array.arrayData). Since you're not doing anything with the returned value, it is just thrown away. So, a new array is created and then thrown away. Nothing else is affected.

The wiki article to which you linked, showed a slightly different statement:

self.myArray = [self.myArray arrayByAddingObject:myNewObject];

In that case, it is the assignment to the property which generates the KVO change notification.

An important concept to understand is that KVO observes the object which has the property for changes in that property. In your case, KVO is observing the object referenced by self.array at the time you added the observer. It is observing it for changes in its arrayData property.

The reason this is important is that KVO is not observing the array itself. That's a point of confusion for many folks when they're new to KVO. Modifying the array (for example, if it were a mutable array) would not generate any KVO change notifications.

All KVO-compliant changes must occur through messages to the observed object (self.array in your case). Here are some of the messages to the self.array that would generate change notifications for its arrayData property:

  • -setArrayData:, the property setter. KVO recognizes the property setter using naming conventions, so the setter name must be of the form -set<Key>:.
  • Since it's apparently an indexed to-many relationship property, any of the mutable indexed accessors, such as -insertObject:inArrayDataAtIndex: or -removeArrayDataAtIndexes:. You would need to implement such accessors on the class which has the arrayData property. If the property is backed by an NSMutableArray, those methods can be simple pass-throughs to the similar methods on NSMutableArray.
  • Explicit invocation of the -willChange... and -didChange... methods of the NSKeyValueObserving informal protocol, specifying @"arrayData" as the key. This is generally discouraged.
  • Using KVC methods such as -setValue:forKey:, specifying @"arrayData" as the key. This will work even in the absence of proper accessors so long as the instance variable is named either _arrayData or arrayData and the class method +accessInstanceVariablesDirectly hasn't been overridden to disable it. Relying on direct instance variable access is really discouraged because it violates encapsulation.
  • Obtaining a KVC mutable array proxy for the property using -mutableArrayValueForKey: and then sending NSMutableArray mutation methods to it. This will actually use one of the above mechanisms to modify the property, so it's actually redundant but it's good to know about.
Ken Thomases
  • 88,520
  • 7
  • 116
  • 154
  • Great answer! I'll run through this, give it a go and update my question if I get it! Thanks! – SirJay Oct 13 '14 at 13:09