【问题标题】:Is scoping the controller's code under a custom view a good cocoa design pattern?在自定义视图下确定控制器代码的范围是一个好的可可设计模式吗?
【发布时间】:2017-06-06 12:59:50
【问题描述】:

当我在考虑 Cocoa 中 MVC 的所有化身时,我想我可以为应用程序中的每个视图创建一个自定义类,并用数据源和委托填充它 - 主要考虑用于控制器的东西。

这样,我可以砍掉一些代码,将它们与它们的数据源和委托一起放在单独的文件中——一个视图一个类——而不是臭名昭著的 Massive-View-Controller。

这是个好主意,还是有什么缺点?

【问题讨论】:

  • 我建议使用 MVVM 模式,在这种模式下,视图控制器更像是视图,而视图模型负责大部分工作。然后,您可以通过注入不同的视图模型来重用视图控制器,只要它们符合特定协议即可。它是你可以调查的。我不喜欢子类化视图,但我知道其他开发人员这样做,但这不是我的风格。
  • @matt_roo 我建议的设计属于 MVVM 还是其他一些 MVC 保护伞?

标签: ios cocoa model-view-controller


【解决方案1】:

恐怕您的想法听起来会导致您最终得到一堆臃肿的视图,而不是一堆臃肿的控制器。

我的建议是考虑Single Responsibility Principle:一个实体应该只有一个目的或功能。视图的功能是什么?

它是屏幕区域的代码表示。这意味着它需要做两件事:绘制到它的区域并注册与该区域的交互。对这两个子任务来说不是绝对必要的任何东西都不应该在视图类中。

这就是“哑视图”的概念。它没有逻辑,没有决策可做。它只是得到一些数据来渲染。当它被点击或点击时,它不知道输入代表什么,或者试图弄清楚如何处理它。它只知道交互的类型并告诉另一个对象。

另一个对象是视图的控制器。视图控制器的职责是在视图和系统的其余部分之间进行调解。它为视图提供数据。它还接受来自视图的有关输入的消息,然后根据这些消息的结果重新配置视图。

但是,视图控制器不一定需要自己计算结果。这通常是视图控制器开始陷入“巨大”麻烦的地方。视图控制器应该选择另一个对象来帮助它获取交互产生的新值。

另一个对象的一种可能性是视图模型,在MVVM structure 中。视图模型是视图原始数据的以显示为中心的表示。它将模型中的信息转换为视图需要的任何格式,并重新转换或更新数据以响应来自视图控制器的输入。

另一个想法是使用VIPER 安排更精细地划分职责。这里数据的格式化由“Presenter”处理,数据的转换是“Interactor”的工作。

在这里进入建筑宇航员领域是可能的;如果视图的需求本质上非常简单,那么盲目地应用复杂的结构可能会咬你一口。但即使您选择不正式应用这些替代模式之一,视图控制器也需要其他对象。您将需要具有其他特定作业的“控制器”,从视图控制器获取消息并将数据传回。

重要的是要牢记我提到的最初想法:努力让每种类型做一件事并做好。这将使您的课程保持专注;易于阅读、理解和思考;并且可测试。

【讨论】:

  • 为什么我的方法不符合单一职责?每个 UIView(及其自定义实例)都有一个单独的职责 - 处理屏幕上的给定区域。每当有人想要更改与给定 Control/button/View/whatevs 相关的任何内容时,他们都会在一个类中找到它。所以我似乎反对那个神圣的原则,只是责任的观点不同。我会遇到哪些潜在问题?另外,它在哪些方面比苹果最初的 MVC 差?
  • 您也可以说应用程序委托的职责是处理单个应用程序。每当有人想要更改与应用程序行为相关的任何内容时,他们都会在一个类中找到它。为什么不这样做?
  • 确实,问题在于粒度以及如何定义职责。对所有事情都使用应用程序代理的问题是有问题的,因为您最终会得到一个巨大的文件,并且不会帮助您理解该项目。当我使用问题中描述的方法时,我遇到了什么问题,即为什么我将事情分解为责任的方式不如你的方式? (我相信是,但我不明白为什么)
【解决方案2】:

View 不计算它的数据,它只是显示它们。但是,如果您有自定义控件,它可以有一些逻辑来计算其内部数据以触发模型内部的值更改。

您的方法是使用不必要的代码的过度杀伤力。

所以您面临一个问题,您需要设置自定义 NSView 或自定义 NSControl 的一些值(例如 NSButton 标题)。

一些可用的 MVC 解决方案:

  1. 手动设置控制器内部的值,并在已更改属性的视图内调用 setNeedsDisplay 方法。
  2. 将模型对象设置为视图的属性。但是,这会引入紧密耦合,但仍然可以(因此视图必须 知道/导入模型类)。 +在视图中包含更新/刷新方法
  3. 使用到 nsobjectcontroller 的绑定。您不需要设置 nsobjectcontroller 的类(仅当您需要额外的 它的功能,例如在添加时自动创建对象 方法)。

MVC 模式提醒 View 具有在控制器中触发的目标动作机制。控制器更新模型(仅此而已!)。然后模型必须传播它已经改变并且控制器应该对它做出反应。它不应该在目标操作中做出反应。

使用绑定可以跳过目标操作,但后者仍然存在

你可以结合2和3。

如果您是初学者,请忘记 VIPER 模式。 MVVM 可以帮助您减小控制器的大小。

如何使用 NSObjectController 绑定:

#import <Foundation/Foundation.h>

#import "AppDelegate.h"
#import "Value.h"
@interface AppDelegate ()

@property (weak) IBOutlet NSWindow *window;
@property (weak) IBOutlet NSObjectController *objectController;
@property (strong) Value *value;
@end

@implementation AppDelegate

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    self.value = [[Value alloc] init];
    self.objectController.content = [self value];
}

@end

@interface Value : NSObject

@property NSString *value1;
@property NSString *value2;
@property NSString *value3;

@end

#import "Value.h"

@implementation Value

- (instancetype)init
{
    self = [super init];
    if (self) {
        [self setValue1:@"Value1"];
        [self setValue2:@"Value2"];
        [self setValue3:@"Value3"];
    }
    return self;
}

@end

【讨论】:

  • 如果有人有更新/发现错误,我会非常高兴!
【解决方案3】:

还有unload View Controllers with Coordinator objects 的选项。很快:应用程序中的每个任务都由一个 Coordinator 对象管理,该对象管理其视图控制器。

有一个主 Coordinator 对象,由应用程序委托保留,并保留所有其他控制器。所有不属于 View Controller 的逻辑,都被移到了 Coordinator 中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-09-02
    • 2021-05-24
    • 1970-01-01
    • 2014-02-05
    • 1970-01-01
    • 2011-04-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多