0

I have a UIView subclass CustomView that has a property CustomObject *model, as well as a couple IBOutlet properties. CustomObject has two properties, an NSString *title and NSString *imageName. I would like an easy, extensible way to update CustomView's various outlets whenever anything in model changes. I feel like there should be some easy way to do this using KVO, but since a new object can be assigned to model, I can't just subscribe to those notifications.

I can think of one way to do this (which I have used before) is to override - (void)setModel:(CustomObject *)model to redo my layout and resubscribe to that object's keys for KVO. Is this the most reasonable solution, or am I overlooking something obvious?

Ned
  • 6,280
  • 2
  • 30
  • 34
  • Just so I'm clear, your VIEW has a custom object property? I think that is going to make coding a lot harder than it needs to be. Usually you want the ViewController to have access to the model and IT updates the View – Pinwheeler Apr 10 '13 at 01:15
  • That's correct. I built it that way so that the view has a clear idea of the model it is portraying. Maybe it would be better to just let the view controller assign those properties on the view. – Ned Apr 10 '13 at 01:38
  • There are many variations on MVC. Having the view observe changes in the model and update itself is one of many commons styles. – rob mayoff Apr 10 '13 at 03:10

3 Answers3

0

having the View have control of the properties goes against MVC design, which while possible makes things a lot harder. I would recommend that you create a ViewController custom subclass and let it pass information to the view through many different methods, one of which is delegation/protocool assignment another of which is notifications.

Pinwheeler
  • 1,061
  • 2
  • 13
  • 26
0

I was going to suggest KVO, before I'd even read through your question, so, having gotten to the end of your question, I'd have to say, yes, this is exactly what KVO is for. But I also agree with the other answer (from Pinwheeler) - it is not the view that should do the observing, but a view controller.

However, it is more usual for the view controller, if possible, to manage both the model and the view. Since it is in charge of both, it doesn't need to observe anything; it knows if the model changed because it changed the model.

matt
  • 515,959
  • 87
  • 875
  • 1,141
0

I handle this by overriding setModel: like this:

- (void)setModel:(Model *)model {
    if (model != _model) {
        [self disconnectFromModel];
        _model = model;
        [self connectToModel];
    }
}

and in dealloc I also call disconnect:

- (void)dealloc {
    [self disconnectFromModel];
}

In connect, I establish connections to the model, if I have one, and I pass the model (or some part of the model) down to my subviews if appropriate. Example:

- (void)connectToModel {
    if (_model) {
        // Maybe start KVO...
        [_model addObserver:self forKeyPath:@"name"
            options:NSKeyValueObservingOptionInitial context:&MyKVOContext];

        // Or maybe register for notifications...
        nameNotificationObserver = [[NSNotificationCenter defaultCenter]
            addObserverForName:ModelNameDidChangeNotification object:_model queue:nil
            usingBlock:^(NSNotification *note) {
                [self modelNameDidChange];
            }];

        // Maybe pass part of the model down to a subview...
        [self.addressView setModel:model.address];
    }
}

In disconnect, I simply undo what I did in connect:

- (void)disconnectFromModel {
    if (_model) {
        [_model removeObserver:self forKeyPath:@"name" context:&MyKVOContext];

        [[NSNotificationCenter defaultCenter] removeObserver:nameNotificationObserver];
        nameNotificationObserver = nil;

        [self.addressView setModel:nil];
    }
}

Note that if you do have subviews that also observe the model, the change of model happens in two passes. First, the entire view hierarchy disconnects from the old model. Then the entire view hierarchy connects to the new model.

rob mayoff
  • 375,296
  • 67
  • 796
  • 848