Avoiding coupling in a document-based Cocoa app?

289 views Asked by At

I'm new to Mac programming and I'm working on a document-based application.

My NSDocument subclass creates a NSWindowController subclass. This window controller creates two NSViewController subclasses as well.

Sometimes, a change in one of the views of a NSViewController needs to notify the NSDocument and/or the main model class. Also, a change in the model needs to be notified to every/some view(s).

My question is: what is the best approach so that there is no (or minimum) coupling? I know there are several choices, but I'm not sure which one suits best for my application as I'm newbie not to programming but to Cocoa and especially NSDocument:

  • KVO. Looks nice and easy to implement, but I don't like the idea of not explicitly notifying the observer(s) about a change (AFAIK, self.someProperty = newValue does automagically notify observers), and don't like the fact that you have to register to property names which could change in time.

  • Notifications. I know what they are and I've used them for iOS. But I've read somewhere that they are not guaranteed to be sent immediately to observers. Is it true? If not, do you see them as a good approach for a document-based app?

  • Delegates. Yes, under normal conditions (or what I've usually seen), a class has one delegate. But creating an array of delegates works as well (just tested it). The problem I see here is that every time I need to notify the delegates I have to loop through them, make sure they respond to a method, and call that method.

Are there any other alternatives I'm missing?

2

There are 2 answers

4
Andrew Madsen On BEST ANSWER

KVO by a controller class is the most common way to do coupling between a model and its view(s). In fact, Cocoa Bindings, which are intended to mostly eliminate code in the controller layer, are based on KVO. It is true that KVO/KVC relies on property names, and that if those change, you'll have to change the bindings or KVO setup connecting your view. However, it's not usually feasible to make your views completely unaware of the underlying model specifics, so I don't see this as a problem.

My recommendation would be to use Cocoa Binding where you can, as they eliminate a lot of glue code. In places where they can't be used, your controllers (the middle layer in MVC) should use KVO to observe model changes and update the appropriate views. Changes in the views can be passed back to the model via property accessors and/or KVC by the controllers.

1
Caleb On

Yes, under normal conditions (or what I've usually seen), a class has one delegate. But creating an array of delegates works as well (just tested it).

Delegates are often used to modify the behavior of the delegating object. An application delegate is a good example: NSApplication by itself isn't very interesting; it relies on its delegate to define the interesting behavior of the application. Having multiple delegates all trying to modify the behavior of a single object could be a problem if the various delegates conflict with each other. What do you do if the delegates disagree?

There are some cases in Cocoa where a class uses more than one delegate, but each one has a separate role. For example, NSTableView has both a delegate and a data source, but both are really delegates of a sort.

The problem I see here is that every time I need to notify the delegates I have to loop through them, make sure they respond to a method, and call that method.

That's not hard to solve. For example, you could create an NSInvocation to encapsulate the call, and then send the invocation to each "delegate." However, if you do that you'll have nearly reinvented the notification system. If you need the one-to-many communication that you'd get with your multiple delegates proposal, you'll probably be better off using notifications or KVO.