Z S Z S - 5 months ago 72x
Objective-C Question

adding KVO to UITableViewCell

I have a custom UITableViewCell which is displaying various attributes of a Person object (backed by Core Data) ... some labels, images etc. I currently force the whole tableview to reload whenever any property changes, and that's obviously not efficient. I know with KVO, I should be able to add a listener to a label in the cell that can listen for changes in the Person's properties. But I'm not sure how to implement it and can't find any examples.

Here's what I typically do in my UITableView's cellForRowAtIndexPath:

- (UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *) indexPath
static NSString *simple = @"CustomCellId";

CustomCell *cell = (CustomCell *) [tableView dequeueReusableCellWithIdentifier:simple];

if (cell == nil)
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:self options:nil];

for (id findCell in nib )
if ( [findCell isKindOfClass: [CustomCell class]])
cell = findCell;
Person *managedObject = [self.someArray objectAtIndex: indexPath.row];
cell.namelabel.text = managedObject.displayName;
return cell;

The cell is hooked up in IB. I would want to detect when displayName changes, and update just the name label.


For background, you probably want to read the Key-Value Observing and Key-Value Coding Guides, if you haven't already. Then review the NSKeyValueObserving category methods.


In a nutshell, you need to carefully manage adding and removing the observing object to the observed objects list of observers (pardon the seeming redundancy of that statement). You don't want to have an object going away with observers still registered, or you get complaints and possible other issues.

That said, you use -addObserver:keyPath:options:context to add an object as an observer. Context should be a statically declared string. The options argument controls what data you get back in your observation method (see below). The keyPath is the path of property names from the observed object to the observed property (this may traverse multiple objects, and will be updated when intermediate objects change, not just when the leaf property changes).

In your case, you could observe the label, and use the text keyPath, or the cell, and use the nameLabel.text key path. If the table view class were designed differently, you might observe the entire array of cells, but there is no such property on UITableView. The problem with observing the cell is that the table view might delete it at any time (if your design uses multiple cells that serve the same purpose in a variable-length list). If you know your cells are static, you can probably observe them without worry.

Once you have an observer registered, that observer must implement -observeValueForKeyPath:ofObject:change:context:, confirm that the context matches (just compare the pointer value to your static string's address; otherwise, invoke super's implementation), then look into the change dictionary for the data you want (or just ask the object for it directly) and use it to update your model as you see fit.

There are many examples of KVO in sample code, including on Apple's developer site, and as part of the bindings samples on Malcolm Crawford (mmalc)'s site, but most of it is for Mac OS X, not iOS.