This is a Cocoa n00b question - I've been programming GUI applications for years in other environments, but now I would like to understand what is "idiomatic Cocoa" for the following trivialized situation:
I have a simple custom NSView
that allows the user to draw simple shapes within it. Its drawRect
implementation is like this:
- (void)drawRect:(NSRect)rect
{
// Draw a white background.
[[NSColor whiteColor] set];
NSRect bounds = [self bounds];
[NSBezierPath fillRect:bounds];
[[NSColor blackColor] set];
// 'shapes' is a NSMutableArray instance variable
// whose elements are NSValues, each wrapping an NSRect.
for (NSValue *value in shapes)
{
NSRect someRect;
[value getValue:&someRect];
[self drawShapeForRect:someRect];
}
// In addition to drawing the shapes in the 'shapes'
// array, we draw the shape based on the user's
// current drag interaction.
[self drawShapeForRect:[self dragRect]];
}
You can see how simple this code is: the shapes
array instance variable acts as the model that the drawRect
method uses to draw the shapes. New NSRect
s are added to shapes
every time the user performs a mouse-down/drag/mouse-up sequence, which I've also implemented in this custom view. Here's my question:
If this were a "real" Cocoa application, what would be the idiomatic way for my custom view to update its model?
In other words, how should the custom view notify the controller that another shape needs to be added to the list of shapes? Right now, the view tracks shapes in its own NSMutableArray
, which is fine as an implementation detail, but I do not want to expose this array as part of my custom view's public API. Furthermore, I would want to put error-checking, save/load, and undo code in a centralized place like the controller rather than have it littered all over my custom views. In my past experience with other GUI programming environments, models are managed by an object in my controller layer, and the view doesn't generally update them directly - rather, the view communicates when something happens, by dispatching an event, or by calling a method on a controller it has a reference to, or using some similarly-decoupled approach.
My gut feeling is that idiomatic Cocoa code would expose a delegate
property on my custom view, and then wire the MyDocument
controller object (or another controller-layer object hanging off of the document controller) to the view, as its delegate, in the xib file. Then the view can call some methods like shapeAdded:(NSRect)shape
on the delegate. But it seems like there are any number of other ways to do this, such as having the controller pass a reference to a model object (the list of shapes) directly to the custom view (feels wrong), or having the view dispatch a notification that the controller would listen to (feels unwieldy), and then the controller updates the model.