0

我的第一个应用程序在 iphone/ipad 上运行,它使用核心图形和手势识别器(不是 OpenGL 或触摸事件)。应用程序、视图和控制器是使用 IB 设置的。它只是 ViewController 中的一个 View。我添加了 CG 调用以绘制到 CG 上下文中。手势被添加到视图中,但在视图控制器中处理。视图控制器使用访问器来更改决定在视图中绘制什么的变量。计算(即模型)嵌入在视图中。该应用程序运行良好,但我想添加功能,例如通过电子邮件发送和保存已绘制的内容。(我知道我需要其他图形上下文)。

传统智慧告诉我我需要使用 MVC 范式,这意味着将模型从视图中分解为自己的对象。所以,我重新分解了代码。我为模型手动添加了一个 NSObject,它很好地包含了数据和所需的方法。没有编译错误或警告。

现在,当视图的 drawRect 被触发时,我想通过控制器从模型中获取更新的图像。在我希望返回图像的关键位置,NULL 回来了。我可能只是没有正确的对象引用,但是我太困惑了,无法消除迷雾,而且我正在真空中工作,所以我正在寻求您的帮助。谢谢阅读。

总结和问题

视图控制器始终具有可以传递给模型的当前参数。该模型可以在给定这些参数的情况下计算位图图像。我很确定我有那么多。

我的问题是(用各种不同的方式表达):

将图像从模型获取到视图的最佳方法是什么(通过控制器:^)视图应该如何向视图控制器发送消息以发起请求?

模型如何将图像返回给控制器?我假设我只是通过您推荐的任何链将 CGContextRef 传回。

关于我:我是 OOP、Objective-C、Xcode 和 IB 的新手。我多次观看了斯坦福大学的大部分讲座,研究了 Goldstein 的傻瓜书,浏览了 Apple 文档。菜鸟很难从这些来源中收集到适当水平的答案。我只是需要更多的“经验”。我太绿了,我什至不知道如何引用视图控制器,除了在视图的接口定义中包含“myViewController *viewController”!我一直在谷歌上搜索并阅读 Stackoverflow 上类似问题的答案。我不敢相信我没有找到任何合适的东西。我希望有一两个实用的原则可以作为我的指导。

请指教。

这类似于reference-to-model-data-in-a-view-instance-drawrect,没有得到满意的回答。

4

4 回答 4

0

如果我理解正确,当模型中的图像发生变化时,视图需要获取新图像。正如威尔所说,您可以使用通知或键值观察。因为你的模型不应该知道视图并且视图不应该对模型有很强的引用。为此,请将其添加到视图控制器中的 viewDidLoad 方法中:

[model addObserver:self.view forKeyPath:@"<replace this with the name of the image property in the model>" options:NSKeyValueChangeNewKey context:NULL];

然后在你的 uiview 子类中创建这个方法:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if ([keyPath isEqual:@"<replace this with the name of the image property in the model>"] {
         // set an image property that has been added to the uiview
         // the image property should be a weak reference ie. (nonatomic, assign)
         self.image = [change valueForKey:NSKeyValueChangeNewKey];
         [self setNeedsDisplay];
    }
}

最后在您的 drawRect: 方法中,您应该绘制图像。

于 2011-01-24T00:01:59.160 回答
0

我如何设置视图之间的链接 | 控制器 | 模型:

view|controller - 从视图控制器的 loadView 方法中,我向视图发送了一条消息“hello:”,其中包含对“self”的引用。在(视图对象的)hello 方法中,我将该指向视图控制器的指针隐藏在全局变量中以供以后使用。

控制器|模型 - 我让视图控制器分配/初始化模型对象的实例,并将指向该实例的指针保存在视图控制器的全局变量中。

我能够使用这两个指针作为从视图到模型的桥梁,方法是通过 vew 控制器上下移动。我不知道我做得好到足以知道我是否可以与 IB 建立这种联系。

工作原理回顾

drawRect 向视图控制器发送更新图像的请求/消息。

视图控制器可以随心所欲地行动,但由于它具有由手势处理程序调整的参数,它可以使用这些参数将特定请求传递给模型。

然后模型开始处理 CG,使用 CGBitmapContextCreateImage(来自模型中的位图上下文)并返回一个 CGImageRef(给视图控制器)。然后视图控制器只返回与原始请求结果相同的 CGImageRef。drawRect 然后 [[UIImage imageWithCGImage:modelImage] drawInRect:rect] 将图像放置在视图中。

可能的缺点,最后的想法

它/可能/更慢,但这可能只是偏执狂。该模型通常绘制 8K 或更多的线来制作位图图像,但视图不必做太多工作来复制生成的像素。我应该使用 Instruments 来看看发生了什么。

我也担心图像质量。似乎还可以。我认为通过首先绘制到 CGbitmap 上下文,然后通过 CGBitmapContextCreateImage,最后是 UIImage imageWithCGImage,我不会失去任何东西。所有相同的确切尺寸。

于 2011-01-25T07:32:15.503 回答
0

如果适合您,您可以尝试的一件事是使用 NSNotifications。

View 获取手势信息并将高级事件发送到 Controller(通过直接消息传递)。控制器接受这些高级事件并对模型进行更改。模型使用这些更改,然后将 NSNotifications 发送给关注更改的任何人。

视图已经知道模型,因为它是如何获取数据来显示的,因此视图将能够轻松订阅这些更改。模型并不真正了解视图,因此必须直接向它发送消息。但是,某处的某些东西对模型更改感兴趣,因此它使用 NSNotifications 来广播和发布该信息。这样,特别是对于复杂的模型和/或更简单的视图,视图只订阅他们感兴趣的内容。您还可以轻松地一次让多个视图(或其他)监听 NSNotifications。

另一个选项是 iPhone 支持的 Key Value Coding/Observing,但它不像 Mac 上的 Cocoa 那样根深蒂固。这会为您半自动处理大部分通知内容,因此您可能也需要考虑这一点。

于 2011-01-23T23:22:17.237 回答
0

首先,只要您的参数会导致数据发生变化,您可能需要重新绘制。因此,当视图需要重绘时,不要请求新数据,而是让视图或视图控制器监视数据,以便如果它发生更改,视图将重绘。drawRect 真的不应该请求数据,尤其是不间接地从视图控制器请求数据,这破坏了整个 MVC 设计,因为视图需要知道它的视图控制器(因此它可以请求数据)。其次为了速度,使用 cgcontext 直接绘制图像:CGContextDrawImage(GContextRef c, CGRect rect, CGImageRef image);.

于 2011-01-25T12:47:56.130 回答