3

这是一个 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添加新的 s,我也在这个自定义视图中实现了这一点。shapes这是我的问题:

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

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

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

4

3 回答 3

5

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

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

于 2009-03-25T12:10:12.270 回答
2

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

于 2009-03-25T15:16:54.507 回答
1

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

于 2009-03-25T12:09:20.697 回答