【问题标题】:MVC - does the view know the controller?MVC - 视图知道控制器吗?
【发布时间】:2013-03-25 22:07:07
【问题描述】:

我目前正在重构我的应用程序以确保它符合 MVC。 我想拆分控制器(扩展 UIController 的 MyController)和视图(扩展 UIView 的 HomeView)我使用

在 myController 中设置视图
self.view = [[HomeView alloc] init];

当我按下 UIButton 时,视图中会调用一个方法,而在这个方法中我想从控制器调用一个方法。

在我看来

[zenModeBtn addTarget:self action:@selector(touchZenMode:) forControlEvents:UIControlEventTouchDown];

...

- (void) touchZenMode:(id) sender {
   [myController playZenMode];
}

但是在视图中引用控制器确实是一种不好的做法,不是吗?

编辑:

所以在我的 UIViewController 中我做了这个:

- (id) init {
    HomeView* myHomeView = [[HomeView alloc] init];
    [myHomeView.arcadeModeBtn addTarget:self action:@selector(touchArcadeMode) forControlEvents:UIControlEventTouchUpInside];
    self.view = myHomeView;
    return self;
}

对吗?

【问题讨论】:

    标签: ios cocoa-touch cocoa model-view-controller


    【解决方案1】:

    在 Cocoa Touch 中使用的 MVC 模式的基本思想:

    如此处所述:The Model-View-Controller Design Pattern

    您想要实现的是一种松散的,甚至可能是盲目的耦合。通过使用协议(用于委托机制),View 只知道有一个采用特定协议的对象,它可以与之“对话”。

    UITableView 为例。它不需要知道有某种类型的UIViewController 可以帮助它收集数据,而只需要知道有一个对象采用UITableViewDatasourceDelegate 和/或UITableViewDelegate;该对象可以是任何类型。

    在您的编辑中,您使用目标-动作机制,这是实现松散耦合的另一种方式。您在运行时设置连接;你的视图不知道你的控制器。因此:正确,除了 @Mundi 关于您的 init 实现不完整的评论

    【讨论】:

      【解决方案2】:

      您可以将该方法放入视图界面中的协议中:

      @protocol MyViewDelegateProtocol <NSObject>
          -(void)myMethod;
      @end
      
      • 您在视图中添加了一个名为 delegate 的 NSObject 类型的新属性。
      • 您让视图控制器遵守该协议,并在它启动视图时将委托属性分配给 self。
      • 您在视图控制器实现中实现 myMethod。
      • 现在您只需在需要时从您的视图中调用 [delegate myMethod]。

      【讨论】:

        【解决方案3】:

        与您的控制器对话的视图没有问题,正如这里的一些答案所概述的那样。例如。文本字段可以通过定义的委托方法通知其控制器。

        但是,您的设计仍然存在严重缺陷。您的视图完全没有处理按钮按下本身的事务。您认为视图不应该知道其控制器的直觉是正确的。

        您的控制器应该知道按钮以及如何对被点击做出反应。这就是为什么控制器有按钮IBOutlets 来告诉按钮例如更改其标题或启用状态。它有按钮处理程序来响应 UI 事件。处理这个逻辑是控制器的工作。显示标题、灰显或将点击事件发送回控制器是视图的工作。

        您应该放入视图中的唯一代码基本上是如何绘制自身。 无法由控制器处理的所有内容。

        【讨论】:

        • 谢谢,但是按钮也必须被绘制,所以我必须把它留在视图中对吗?
        • 对。在控制器中创建和配置按钮。请记住,控制器控制视图。 -- 但是你的编辑是错误的。在init 中,您必须调用[[super alloc] init] 来创建self
        • 是的,你是对的,我应该调用父构造函数 UIViewController 但似乎 self = [[super alloc] init];触发错误“'UIViewController' 没有可见的@interface 声明选择器'alloc' 任何线索?
        • [super init] 有效,对吗? (没有alloc,我猜它是自分配的?)
        • 是的,你不在 init 方法中分配。我的错。
        【解决方案4】:

        视图需要某种方式将事情传回给控制器,向它询问下一步要做什么等问题。因此,视图了解控制器的某些信息是非常好的。

        一些内置视图,如 UITextField,定义了它们用来告诉委托人正在发生的事情或要求它做某事的协议。您通常在控制器中实现协议。这样,视图对控制器的了解并不多,仅足以进行通信。这使您的视图更加通用和可重用。

        您要避免的是让您的视图直接链接到您的模型。控制器的作用是在视图和模型之间进行调解。您应该能够在不接触模型的情况下完全更改视图的实现方式,反之亦然。

        【讨论】:

          猜你喜欢
          • 2012-02-02
          • 1970-01-01
          • 2010-10-03
          • 1970-01-01
          • 1970-01-01
          • 2020-02-21
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多