传递参数视图模型或协议

时间:2016-06-07 02:58:31

标签: swift struct swift2 swift-protocols

代码取自Protocol Oriented MVVM,这就是ViewModel的样子:

struct MinionModeViewModel: SwitchWithTextCellDataSource {
    var title = "Minion Mode!!!"
    var switchOn = true
}

extension MinionModeViewModel: SwitchWithTextCellDelegate {
    func onSwitchTogleOn(on: Bool) {
        if on {
            print("The Minions are here to stay!")
        } else {
            print("The Minions went out to play!")
        }
    }

    var switchColor: UIColor {
        return .yellowColor()
    }
}

我理解这一部分。基本上,MinionModeViewModel覆盖了SwitchWithTextCellDelegateSwitchWithTextCellDelegate的某些默认行为

接下来,作者通过传递viewModel作为参数来配置单元格:

SettingsViewController.swift

let viewModel = MinionModeViewModel()
cell.configure(withDataSource: viewModel, delegate: viewModel)
return cell

但是,在SwitchWithTextTableViewCellconfigure方法的参数为SwitchWithTextCellDataSourceSwitchWithTextCellDelegate

func configure(withDataSource dataSource: SwitchWithTextCellDataSource, delegate: SwitchWithTextCellDelegate?) {
        self.dataSource = dataSource
        self.delegate = delegate

        label.text = dataSource.title
        switchToggle.on = dataSource.switchOn
        // color option added!
        switchToggle.onTintColor = delegate?.switchColor
    }

我是Swift的新手。有人可以解释一下

  1. dataSourcedelegate方法的名称及其含义configureSwitchWithTextTableViewCell是什么。他们是External Parameter Names

  2. 为什么configure方法的传递参数类型不同:view model vs protocols类型

2 个答案:

答案 0 :(得分:2)

首先,MinionModeViewModel不会覆盖SwitchWithTextCellDelegate和SwitchWithTextCellDelegate的默认行为。

术语覆盖与继承一起使用。 实施例

class A {
  func someFunction() {
  }
}
class B:A {
  override func someFunction() {
  }
}

这里的类B是类A的子类,因此如果类B应该提供方法someFunction的不同实现而不是类A,它应该覆盖它并提供不同的实现。

协议不同。它是一种抽象的类。协议只是一套规则。 因此,当某个类或结构符合协议时,它意味着它们应该实现协议定义中声明的所有必需的方法或属性。

示例:

protocol SwitchWithTextCellDelegate {

  func onSwitchTogleOn(on: Bool)

  var switchColor: UIColor {get}
}

现在任何符合协议SwitchWithTextCellDelegate的结构或类都应该实现onSwitchToggleOn方法,并且还应该有一个具有getter的属性switchColor。

就像你做过的那样:

extension MinionModeViewModel: SwitchWithTextCellDelegate {
    func onSwitchTogleOn(on: Bool) {
    }

    var switchColor: UIColor {
        return someColor
    }
}

方法说明

1. func configure(withDataSource dataSource: SwitchWithTextCellDataSource, delegate: SwitchWithTextCellDelegate?)

dataSource :在此参数中,我们可以传递符合协议SwitchWithTextCellDataSource protcol的任何类或结构

委托:在此参数中,我们可以传递符合协议SwitchWithTextCellDelegate的任何类或结构

现在,教程的作者在两个参数中都传递了相同的对象,这可能会令人困惑。为什么不将它作为单个参数传递?

let viewModel = MinionModeViewModel()
cell.configure(withDataSource: viewModel, delegate: viewModel)

这是因为MinionModeViewModel符合SwitchWithTextCellDataSource和SwitchWithTextCellDelegate协议,因此我们可以在两个参数中传递相同的对象。但是这种方法可以灵活地传递任何符合这些协议的对象。

答案 1 :(得分:1)

协议定义采用对象实现的行为(通常不会覆盖行为)。

在此示例中,SwitchWithTextCellDataSourceSwitchWithTextCellDelegatesprotocols MinionModelViewModel继承(已采用)。为了更有意义,请考虑您可能有另一个结构:

struct EvilVillanViewModel: SwitchWithTextCellDataSource {
  var title: "Evil Villian Model!!!"
  var switchOn = false
}

由于此结构也采用SwitchWithTextCellDataSource,因此只要代码期望实现class的{​​{1}} / struct,它就可以互换 - 因为它知道它将具有SwitchWithTextCellDataSource title和switchOn值 - 因为协议需要它。没有它,您的代码将无法编译。

所以....在configure(withDataSource dataSource: SwitchWithTextCellDataSource...)中,您可以轻松传入EvilVillanViewModel结构或MinionModelViewModel,一切都会完美无缺。当代码块引用dataSource.title时,它知道你传递的内容是title,因为它必须符合SwitchWithTextCellDataSource协议。

这只是协议能力的开始!希望这有帮助!