自定义视图应如何更新模型对象?

时间:2009-03-25 11:50:46

标签: cocoa architecture idioms

这是一个Cocoa n00b问题 - 我在其他环境中已经编程了多年的GUI应用程序,但现在我想了解以下琐碎的情况下什么是“惯用的Cocoa”:

我有一个简单的自定义NSView,允许用户在其中绘制简单的形状。它的drawRect实现是这样的:

- (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]];
}

您可以看到此代码有多简单:shapes数组实例变量充当drawRect方法用于绘制形状的模型。每次用户执行鼠标按下/拖动/鼠标按键序列时,新的NSRect都会添加到shapes,我也在此自定义视图中实现了该序列。这是我的问题:

如果这是一个“真正的”Cocoa应用程序,我的自定义视图更新其模型的惯用方法是什么?

换句话说,自定义视图应该如何通知控制器需要将另一个形状添加到形状列表中?现在,视图跟踪自己的NSMutableArray形状,这可以作为实现细节,但我不希望将此数组公开为自定义视图的公共API的一部分。此外,我想将错误检查,保存/加载和撤消代码放在像控制器这样的集中位置,而不是让它遍布我的自定义视图。在我之前使用其他GUI编程环境的经验中,模型由我的控制器层中的对象管理,并且视图通常不直接更新它们 - 而是视图在发生事件时通过调度事件或通过调用控制器上的方法,它引用或使用一些类似的解耦方法。

我的直觉是,惯用的Cocoa代码会在我的自定义视图上显示delegate属性,然后连接MyDocument控制器对象(或挂起文档控制器的另一个控制器层对象)视图,作为其委托,在xib文件中。然后视图可以在委托上调用shapeAdded:(NSRect)shape之类的方法。但似乎有许多其他方法可以做到这一点,例如让控制器直接将模型对象(形状列表)的引用传递给自定义视图(感觉不对),或让视图发送通知控制器会监听(感觉笨重),然后控制器更新模型。

3 个答案:

答案 0 :(得分:5)

拥有代表是一种cromulent方式来执行此操作。另一种方法是在视图上公开NSArray绑定,并将其绑定到数组控制器的arrangedObjects绑定,然后将数组控制器的content绑定绑定到拥有模型对象的实际数组的任何拥有。然后,您可以在同一个阵列控制器上添加其他视图,例如活动层中的对象列表。

这是一个自定义视图,您需要创建一个IBPlugin以在IB中公开绑定,或者通过向视图发送bind:toObject:withKeyPath:options:消息以编程方式绑定它。

答案 1 :(得分:2)

在/ Developer / Examples / AppKit / Sketch目录中有一个非常好的示例xcode项目,它是您正在进行的更高级版本,但仍然相关。它有很好的例子,可以在控制器和视图之间使用绑定,从而阐明“正确”的做事方式。此示例不使用IB插件,因此您将看到手动调用bind和实现的观察方法。

答案 2 :(得分:1)

您的代码和NSTableView之间有几个相似之处,所以我会考虑使用数据源(类似于您的委托),甚至可能使用绑定。