Swift中如何尊重MVC



我想知道您是如何在使用Swift开发IOS时正确尊重MVC设计模式的我现在的感觉是,视图控制器混合了控制器部分和视图部分,但感觉不对,对吧?为了尊重MVC,我们显然需要将控制器和视图分开你是怎么做的也许,这在MVVM或MVP等其他设计模式中更为明显?

您可以分离您的项目,并创建一个结构,其中所有逻辑和模型都在一个位置,所有viewControllers也在一个地方。

例如:

Core
Models
Person.swift
Car.swift
Helpers
Extensions.swift
APIHelper.swift
Webservice
Webservice.swift

Controllers
ViewController.swift
SecondViewController.swift

因此,您基本上在Core中拥有所有逻辑和计算,在Controllers中拥有所有视图和UI元素。通过这种方式,您不必多次执行相同的逻辑代码。您也可以创建自定义视图,并将它们添加到Core中,稍后可以在Controllers中调用。

虽然回答这样的问题可能过于宽泛,但我将回答您关于的具体问题:

视图控制器混合了控制器部分和视图部分。。。


请注意,在处理iOS项目时,它会隐式地引导您应用MVC模式。默认情况下,视图控制器表示Controller部分,.stebox.xib文件表示View部分,用于封装数据的任何模型对象(数据模板)表示Model

我现在的感觉是视图控制器混合了控制器部分和视图部分,但感觉不对吧?

视图控制器有许多职责需要处理,除了解释用户操作外,它还应该是视图和模型之间的中介,不要忘记处理与web服务的集成。。。这就是大规模视图控制器的问题。

如果你试图做一些关于解决这个问题的研究,你会发现有很多方法可以遵循,比如应用其他结构模式,比如MVVMMVPVIPERClean Architecture或者甚至更简单的方法,比如划分项目文件以增加作业的独立性,从而使其更清晰、更容易跟踪,MVC-N可能是一个很好的例子。

但对于您询问的特定情况(混合控制器部分和视图部分),请保持简单:我建议根据视图分离数据表示的逻辑,例如:

构建iOS项目时最流行的情况之一是使用表视图及其单元格,请考虑以下内容:

ViewController.swift:

class ViewController: UIViewController {
// ...
}
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myDataSourceArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCellID") as! MyCustomCell
// ...
return cell
}
}

MyCustomCell.swift:

class MyCustomCell: UITableViewCell {
@IBOutlet weak var lblMessage: UILabel!
}

现在,想象一下,在这种情况下,需要基于一系列复杂的计算来更改单元格中的lblMessage标签文本颜色:

不要这样做:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCellID") as! MyCustomCell
// do calulations which might needs tens of lines to be achieved, based on that:
cell.lblMessage.textColor = UIColor.red
return cell
}

这导致视图控制器变得庞大,并包含大量作业,而不是:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MyCellID") as! MyCustomCell
//...
cell.doCalaulations()
return cell
}

在单元格类中:

class MyCustomCell: UITableViewCell {
@IBOutlet weak var lblMessage: UILabel!
func doCalaulations() {
// do calulations which might needs tens of lines to be achieved, based on that:
blMessage.textColor = UIColor.red
}
}

这导致项目组件更加封装,重要的是视图控制器不需要来处理整个事情。对我来说,在与此类似的情况下,我甚至更愿意将blMessage设置为private,这保证了它只能从所有者类中编辑(更多的封装),以处理任何需要的行为,因此任何视图控制器都应该调用类方法,而不是直接访问其属性和IBOutlets。

将常用的ViewController分为两个不同的部分:ViewPresenterView响应仅用于显示数据和收集用户交互。Presenter准备用于查看和处理来自View的用户动作的数据。

这个想法源于Bob叔叔的Clean Architecture,并在VIPER架构中实现。

View有两个协议:

  • ViewInput:包含用于传递数据以显示的函数,如set(labelText: String)。该协议应实现View。CCD_ 21具有类型为CCD_
  • ViewOutput:包含函数,当视图中发生某些事件(如viewDidLoad()rowDidSelect(at: IndexPath))时调用这些函数。该协议应实现Presenter。CCD_ 27具有类型为CCD_

VIPER不是一件小事,我花了几天时间来了解它的原理。因此,请阅读文章并尝试在代码中实现它。不要犹豫,提出问题。

最新更新