【问题标题】:IBAction in UIView - Compatible with MVC?UIView 中的 IBAction - 与 MVC 兼容?
【发布时间】:2014-03-08 23:03:11
【问题描述】:

我正在尝试使用 Objective-C 了解 iOS 应用程序中 MVC 模式的实现。

现在我有一个 DataProvider 对象,它保存我的数据并将其提供给我的应用程序(模型)中的其他对象。

此外,我有一个带有附加类(UIView;我们称之为“ViewClass”)的视图(.xib)。我告诉我的视图是我的 ViewClass 的子类,这样我就可以为我的子视图创建IBOutlets,如标签和IBActions 到我的按钮。所以这显然是我在 MVC 模式中的观点。

最后但同样重要的是,我有一个 ViewController 对象,它引用了我的 DataProvider 并保存了我的视图对象。当ViewController 加载到内存中时,它会实例化viewDidLoad 中的视图,并通过调用addSubview:(UIView *)view 将其添加到自己的视图中。这是我在 MVC 模式中的控制器。

到目前为止一切顺利,但我不明白的是以下内容。根据 MCV 模式,视图应该只显示由从模型中获取数据的ViewController 提供的数据。任何逻辑操作都应该只发生在ViewController,因为它负责此类任务。 但是如果我在我的“ViewClass”中创建一个IBAction,我就不得不在我的视图中加入某种编程逻辑。

假设我想提交一个表单,其中包含用户通过单击按钮在某个文本字段中输入的数据。在我的ViewClass 中,我在文本字段中有一个IBOutlet,以便以后能够引用它并读取用户输入的数据。而且我在按钮上有一个IBAction,以便能够捕获点击事件。发送数据的代码现在写在我的视图中的IBAction 方法中,所以我的视图中有程序逻辑。

我的问题:这不是违反 MVC 模式吗?

我可以在创建视图实例时将我的ViewController 的引用传递给我的视图,然后在IBAction 中调用我的ViewController 的方法,然后获取并发送数据。 但我真的无法想象这是正确的方法。还是我理解错了?

提前致谢。

【问题讨论】:

  • 我可能没看懂你的例子,但是你为什么不把 IBAction 放到 View Controller 中呢?视图控制器具有/应该可以访问其所有子视图(递归)。
  • 因为这是不可能的。我只能在我的 View (.xib) 继承的“ViewClass”中创建 IBAction。

标签: ios objective-c xcode model-view-controller ibaction


【解决方案1】:

不确定我是否正确理解了您的视图层次结构,但我不建议将任何属于模型的逻辑放入视图中。

我会让 ViewClass 成为 UIControl 的子类,这样它就可以自己发送事件。如果按钮被按下,您将发送一个由 viewController 接收的 valueChangedEvent。

例如:

// .h
@interface ViewClass : UIControl
@property (readonly, nonatomic) UIButton *button;   // read only in public interface
@property (readonly, nonatomic) UITextField *textField;
@end

// .m
@interface ViewClass ()
@property (strong, nonatomic) UIButton *button;     // readwrite in private interface
@property (strong, nonatomic) UITextField *textField;
@end

@implementation ViewClass
- (IBAction)buttonPressed:(UIButton *)sender {

    // send valueChanged event to target
    [self sendActionsForControlEvents:UIControlEventValueChanged];
}

@end

还有你的 viewController:

- (void)viewDidLoad {
    [super viewDidLoad];
    ViewClass *myView = ...
    [myView addTarget:self action:@selector(myViewDidChangeValue:) forControlEvents:UIControlEventValueChanged];
}

- (IBAction)myViewDidChangeValue:(ViewClass *)sender {
    NSLog(@"Send \"%@\" to server", sender.textField.text);
}

您也可以将addTarget:forControlEvents: 用于视图的子视图。所以你实际上可以将 ViewClass 的按钮连接到你的 viewController,你可能无法在 Interface Builder 中做到这一点。

[myView.button addTarget:self action:@selector(viewButtonTapped:) forControlEvents:UIControlEventTouchUpInside];

【讨论】:

  • 嗯,这似乎是我正在寻找的方法。
  • 也可以将 ViewController 注册为 Observer 并在 IBAction 中通知 ViewController 并以这种方式调用包含逻辑的方法。你怎么看这个想法?但我想知道这是不是苹果考虑解决这个问题的方式......
  • 有多种方法可以解决这个问题。如果我想将视图连接到 viewControllers,我通常使用这种目标操作模式,因为它花费最少。您可以使用委托,我通常使用它来将 viewControllers 连接到 viewControllers,但它们需要 @protocols 并且对于想要发送单个消息的视图通常没有意义。有 NSNotifications,我用它来连接不相关的模型。最后但并非最不重要的关键值观察,我很少使用。但这只是我。你可以都试一试。何时选择哪种方式本身就是一个巨大的话题。
  • 好的,感谢您抽出宝贵的时间和有能力的回答。我将对这个主题进行更深入的研究,并暂时使用您的目标-动作模式。似乎是目前最好的解决方案。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-04
  • 1970-01-01
相关资源
最近更新 更多