【问题标题】:What is the best (designwise) way to pass an NSArray of model objects to a view object?将模型对象的 NSArray 传递给视图对象的最佳(设计)方法是什么?
【发布时间】:2011-04-04 20:43:40
【问题描述】:

我有一个 BankAccount 模型类,其中包含帐号、银行名称、交易等数据。交易是 Transaction 类的每个实例,并包含在交易 NSArray 中。

我还有一个 BankAccountView,它在一个视图中显示所有这些。现在我将所有数据作为单独的变量传递(即 bankAccountView.accountNumber = bankAccount.accountNumber,bankAccountView.bankName = bankAccount.bankName)。

当我需要将事务传递给视图时,就会出现问题/困境。我学会了将模型类和视图类分开,所以我认为将 BankAccount 的交易数组传递给 BankAccountView 并不是一件好事,因为该数组包含 Transaction 模型类的实例。

所以我现在要做的是:我获取每个 Transaction 实例,将其转换为 NSDictionary,然后将 bankAccountView.transactions 设置为包含这些字典的 NSArray。它可以工作,我觉得它使我的模型和视图类分开,但它也感觉过于复杂,就像我正在编写很多代码来做一些可能更简单的事情。

有没有更好的方法来做到这一点?提前致谢。

【问题讨论】:

    标签: iphone objective-c cocoa-touch model-view-controller oop


    【解决方案1】:

    我认为你已经走得太远了,应该直接传递整个 BankAccount 对象。没有转换,没有环境,只是将它一直传递给视图。你所做的那种分离(对我来说)感觉有点像用大炮向苍蝇射击......

    我的论点:

    • 您的视图只能显示 BankAccounts,为什么不传递它正在显示的对象?
    • 这使您的界面非常清晰,只需要一个属性:@property(...) BankAccount *bankAccount;
    • (EDIT) 传递一个对象封装了所有属性之间的依赖关系。他们不是独立的,他们形成了一个银行账户。这应该是可见的。
    • 无需转换,扩展模型无需更改接口
    • 只有当您的视图独立于它所显示的数据时,才需要模型和视图之间的非常严格的区分。将只能显示一种非常特定类型的数据的视图匿名化是没有意义的:银行账户。
    • 所有转换只有在您组合多个可重用组件的视图时才有意义。你似乎没有,所以这只是不必要的工作。
    • MVC 仍然保留:模型不知道控制器或视图,视图不直接知道控制器,控制器将数据从视图传递到模型并对操作做出反应。

    如果您不想直接传递该类,请设计一个协议来封装视图所需的银行帐户对象的所有属性,并让BankAccount 类实现它。 然而,这只有在您(计划)将不同种类的类作为数据传递给视图时才有意义。如此不同以至于这些类不共享具有所有这些属性的通用超类。如果只有这个简单的类或者继承的类,还是用最简单的办法:直接传账号。

    为了能够在更改时触发重绘,我建议您使用 Key-Value-Observation。这是一种非常干净的方式来保持匿名并且只需要编写很少的代码。在视图中的 init 方法中,对您要观察的每个属性执行以下操作:

    [self addObserver:self forKeyPath:@"bankAccount.<property>" withOptions:0 context:@"redraw"];
    

    然后你实现observeValueForKeyPath...:

    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
    {
        if (context == @"redraw") {
            [self setNeedsDisplay];
        } else {
            [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
        }
    }
    

    我发现这是一种非常干净的方法,开销很少,我碰巧在我自己的项目中大量使用。

    【讨论】:

    • 嗯,这完全回答了我的问题。谢谢!
    • 哦,我对此还有一个额外的问题:之前,我在 BankAccountView 类中为我的每个设置器添加了一个 setNeedsDisplay 调用,这样当我更改其中一个属性时,视图将被重绘。但是现在,我没有更改任何属性,传递的 BankAccount 对象在内部发生了变化。 BankAccountView 跟踪这些更改的最佳方式是什么? BankAccount 是 Core Data 生成的类。
    • 就个人而言,我会使用 Key-Value-Observation。我会在一秒钟内相应地调整我的答案...
    • +1 我希望我能对此给予更多支持。马克斯,这是对很少如此清晰地谈论的事情的精彩讨论。
    【解决方案2】:

    我看待 MVC 范式的方式(记住,它只是一个范式——它可以解释)是模型对视图一无所知,而视图对模型一无所知。他们不应该直接互动;严格来说,你的视图不应该有你的模型的实例。

    这就是 控制器 变得重要的地方。我要假装你的BankAccountView 有一些标签来显示帐户信息,也许还有一个表格视图来显示所有帐户交易(让我们假装,只是为了说明)。那么你会有这样的东西:

    MyBankAccountViewControllerUIViewController 的子类(MVC 中的C),其视图是BankAccountView 的实例。你的视图控制器也有一个BankAccount 的实例。在适当的时候(例如-viewDidLoad),您需要使用BankAccount 模型(self.bankAccountView.accountNameLabel.text = self.myBankAccount.name 或其他东西)中的信息填充您的视图(及其子视图)。

    MyBankAccountViewController 也将充当您视图中 tableview 的委托和数据源,为其提供列出帐户交易信息的单元格。

    当视图中发生需要更改模型的事情时(例如,用户按下“关闭此帐户”按钮),“事件”将从视图发送到控制器(通过委托、目标行动,或您选择的其他一些机制)。然后控制器决定做什么,比如[self.bankAccount closeBankAccount];

    就像我说的,这就是我解释 MVC 的方式(我严格而迂腐地看待它),它可能会使您的代码复杂化,而不仅仅是直接传递模型。如果你只是打算在一个地方使用这个视图,并且从不打算重用它,那么直接传入可能会更简单。请记住,这是以将来更难重用为代价的(这是 MVC 的关键卖点之一:您的模型和视图应该是可重用的;您的控制器不会)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-08-31
      • 2019-04-16
      • 2010-12-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-27
      相关资源
      最近更新 更多