视图是否应包含模型引用?

时间:2013-05-13 07:00:53

标签: ios objective-c oop design-patterns model-view-controller

假设我们有以下课程:

查看

@interface ArticleView : UIView
@property IBOutlet UILabel *titleLabel;
@property IBOutlet UILabel *bodyLabel;
@end

模型

@interface Article : NSObject
@property NSString *title;
@property NSString *body;
@end

控制器

@interface ArticleViewController : UIViewController
@property Article *myArticle;
@property ArticleView *myArticleView;
- (void)displayArticle;
@end

@implementation
- (void)displayArticle {
    // OPTION 1
    myArticleView.titleLabel.text = myArticle.title;
    myArticleView.bodyLabel.text = myArticle.body;    

    // ... or ...

    // OPTION 2
    myArticleView.article = myArticle;
}
@end

选项1

  • PRO:视图和模型都没有相互耦合。
  • CON:控制器需要知道模型和视图的详细信息。

选项2

  • PRO:控制器代码轻巧灵活(如果视图或模型发生变化,控制器代码保持不变。
  • CON:视图和模型是耦合的,因此不太可重复使用。

在选项2中,必须更改ArticleView以保存对模型的引用:

@interface ArticleView : UIView
@property IBOutlet UILabel *titleLabel;
@property IBOutlet UILabel *bodyLabel;
@property Article *article;
@end

然后可以覆盖文章设置器以相应地更新视图,如下所示:

- (void)setArticle:(Article *)newArticle {
    _article = newArticle;
    self.titleLabel.text = _article.title;
    self.bodyLabel.text = _article.body;
}

所以我的问题是,在OO和iOS / MVC最佳实践方面,这两个选项中哪一个最好?

我当然看到两者都被使用了。我见过OPTION 2在UITableViewCell子类中常用。

我还读过,视图和模型应该被设计为可重用而不依赖于任何东西,而视图控制器应该是最不可重复使用的。

我的直觉是使用OPTION 1只是因为我宁愿视图控制器执行将模型绑定到视图的脏工作,让模型和视图保持独立并且彼此不知道。但是,由于某些观点只是为了做一件事,所以将它们直接绑定到特定模型也许并不是那么糟糕。

我很想听听你对此的看法。

6 个答案:

答案 0 :(得分:30)

这并不总是一个或两个决定。你的第一个选择是更典型的Apple版MVC;在iOS中通常是这样的,模型和视图不会直接相互通信,并且控制器完成它们之间的大部分协调。但是,拥有一个知道大型模型中特定类的自定义视图并不是不合理的。您可能有一个知道如何处理文章的ArticleView,但ArticleView仍应接收从控制器显示的任何文章,而不是直接从较大的模型中获取。

MVC的目标之一是使模型和视图类更具可重用性。如果你使ArticleView非常简单,那么控制器必须完成解释文章的所有工作,那么你实际上可能会失去可重用性 - 每次你想要使用新的视图控制器重用ArticleView时,你必须重现解释ArticleView文章的所有代码。或者,您始终使用相同的视图控制器类来管理ArticleView。这些都不是“可重用的”。

同时,您必须承认Article和ArticleView之间存在一些自然耦合,仅仅是因为ArticleView旨在显示文章的所有相关细节,无论是直接来自文章还是由视图控制器设置它们。如果文章发生变化,ArticleView很可能必须改变它是否知道文章。

所以,即使Article可能是一个模型类,也可以有一个了解它的视图。你不想要的是一个ArticleView,它知道更大的模型,并试图从模型本身获取文章。这会将您可以在ArticleView中显示的文章限制为可以在ArticleView外观中找到的文章 - 它会阻止您显示其他来源的文章。

答案 1 :(得分:3)

是的,您已经证明了对该主题的理解。

选项1是MVC的经典结构,我建议将其作为两者的默认路由。

仅仅因为OPTION 1是一个更纯粹的定义,并不意味着它需要在任何可能的地方应用。

我做的最常见的偏差是当一个实现是如此具体而没有被重用时,引入专用控制器类型只会导致更多代码编写和维护,当实现很小,非常专业,不可重用,并且不会增长基本上。如果程序很适合将V和C折叠成单个实现并适合小的(例如几十行代码),我不担心使用OPTION 2.

现实比这更复杂,但要点是:不要觉得你需要坚持#1,尽管你可能不会理解使用#2如何引入维护问题,直到你编写和维护一些几年的中等规模的计划。从一个移动到另一个可以在已发布的程序中引入许多更改 - 这本来是可以避免的。

选项2的使用应该是少数。如有疑问,请使用选项1。

无论哪种方式,我相信模型不应该知道视图或控制器。

对我来说,在编写可重用组件时,严格遵守更为重要。

答案 2 :(得分:1)

坦率地说,有时候我会自己做选项2。但是选项1“不在书中”。

答案 3 :(得分:1)

就Apple关于此主题的官方指导而言, Objective-C Programming中的概念文档的MVC as a Compound Design Pattern部分讨论了这两种方法,但明确阐述了Apple对您的选项1的偏好你的选择2.实际上Cocoa Core Competencies只列出了选项1。

我从来没有后悔实施选项1方法,但是当我偷工减料并试图让模型和视图直接交互时,我常常后悔当我不得不回去修改系统时晚些时候。

答案 4 :(得分:0)

正如其他人所说,选项1是更纯粹的方法。控制器应该是视图和模型之间的“接线盒”。

然而,这种方法的许多实现(例如Microsoft称为MVC的框架)都充满了Option 2.当然,在Microsoft的情况下,View和Model相互了解的事实允许IDE创建许多样板代码,并为您节省“麻烦”。这样做的好处是你花时间编写“功能”代码而不是“连接”代码。所以,无论是否纯洁,你都可以欣赏它们的来源。

正如软件开发中经常出现的那样,选项1和选项2之间的选择归结为纯粹与实用主义。

答案 5 :(得分:-1)

选项1是MVC。选项2不是。

OO实际上处于不同的水平,你有模型,视图和控制器的对象,所以你不能做更多的事情来做OO。

这两个选项当然都有效,但MVC存在是有原因的(我确定你已经完成了一些通用的阅读like this),你会发现你的代码更容易阅读,理解和如果你遵循MVC的原则就重用。