MVC:存储数据的位置?

时间:2017-01-02 13:20:23

标签: swift cocoa design-patterns

我喜欢在Cocoa应用程序中使用模型 - 视图 - 控制器设计模式(用Swift编写)。让我们假设着名人物示例:应用程序应显示文本字段和添加按钮。可以将人名放入文本字​​段,然后通过单击添加按钮将其存储在数组中(并且可以在表视图中显示数组内容)。现在,故事板包含我所有与View相关的内容,而类Person(具有变量名)构成了Model类。视图控制器将负责接收显示数据(例如表视图委托和数据源)并具有提取名称并将其放在某处的IBAction。但是,我不知道在哪里实际放置包含所有名称的数组。我是否也可以在视图控制器中使用它(这是我认为最简单的解决方案)?或者别的地方?如果应用程序在不同视图中使用多个数据保持结构(使用不同的视图控制器)变得越来越复杂,该怎么办?

2 个答案:

答案 0 :(得分:0)

1)ViewController(来自UITableViewController或UIViewController):

class ViewController: UITableViewController, UITextFieldDelegate {

    var model = ViewModel()

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "personCell")
        let nib = UINib(nibName: "InputTableViewCell", bundle: nil)
        tableView.register(nib, forCellReuseIdentifier: "inputCell")

        // Request or load the data into model
        // requestData() & tableView.reloadData() here

    }

    // MARK: - UITableViewDataSource

    override func numberOfSections(in tableView: UITableView) -> Int {
        return 2
    }


    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return section == 0 ? 1 : model.persons?.count ?? 0
    }


    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if indexPath.section == 0 {
            let cell = tableView.dequeueReusableCell(withIdentifier: "inputCell", for: indexPath)
            if let inputCell = cell as? InputTableViewCell {
                inputCell.textField.text = model.input
                inputCell.textField.delegate = self
                inputCell.textField.addTarget(self, action: #selector(textFieldEditing(_:)), for: .editingChanged)
                inputCell.buttonAdd.addTarget(self, action: #selector(buttonAddTapped(_:)), for: .touchUpInside)
            }
            return cell
        } else {
            let cell = tableView.dequeueReusableCell(withIdentifier: "personCell", for: indexPath)
            let person = model.persons?[indexPath.row]
            cell.textLabel?.text = person?.name
            return cell
        }
    }

    // MARK: - Event Handler

    func textFieldEditing(_ sender: UITextField) {
        model.input = sender.text
    }

    func buttonAddTapped(_ sender: UIButton) {
        if let name = model.input, name.characters.count > 0 {
            let person = Person()
            person.name = name
            model.addPerson(person)
            model.input = nil
            // Also save data to CoreData if you want to retrieve them again later
            // saveData()
        }
        tableView.reloadData()
    }


}

2)定义单元格:包括输入单元格或Person单元格(如果需要)。创建新类时,请检查"还要创建XIB文件"也是连接和用户界面。

class InputTableViewCell: UITableViewCell {

    @IBOutlet weak var textField: UITextField!
    @IBOutlet weak var buttonAdd: UIButton!

}

3)定义视图模型:

class ViewModel {

    var persons: [Person]?
    var input: String?

    func addPerson(_ person: Person) {
        if persons == nil { persons = [] }
        persons?.append(person)
    }

}

4)定义模型:

class Person {
    var name: String?
}

答案 1 :(得分:0)

<强>型号:

您需要一个数据库或核心数据。

我将CD分离出来,因为在IT的某些角落,它被认为更像是一个&#34;模型&#34;使用mySQL数据库或后面的XML文件。就像任何可供讨论的人一样,CD有它的优点和缺点。许多人认为实施后扩展事物的最大弱点之一就是。

  

如果应用程序在不同视图中使用多个数据保持结构(使用不同的视图控制器)变得越来越精细怎么办?

对我来说,这是Model的关键,这意味着一个简单的SQL(或关系型)数据库。如果你不知道我对关系的意思,请查阅,花几天时间学习它。 (提示:当你谈论一个&#34; person class&#34;。模型(看我在那里做了什么?)你的类匹配 - 通过名称,类型和属性 - 你的数据库表时,你已经在那里了。 1:1你可以做得越好。

但请记住可扩展性和层级(模型,视图,控制器)。 Swift计算了属性。如果你在查询类似于&#34;有多少人住在欧洲&#34;你最好使用SQL - 它使数据通过管道清洁器,并且表现更好。但是,如果你想展示类似于&#34; John Doe生日那天多少天&#34;你可能最好在控制器方面做一个计算属性或一个可调用函数。

您还想决定本地或云端。 Facebook显然在云中拥有一个数据库。但我的第三方播客应用程序(不是Overcast BTW)有一个本地数据库。

查看:

你似乎对此有了很好的把握。 Xcode在大多数情况下都很好地坚持使用MVC。如果您能够完全坚持使用Interface Builder,那么您已经完成了这项工作。

但有些程序员(像我一样)无法做到这一点。对于所有Apple在自动布局限制方面都做得很好,他们做出一些决定我并不知道背后的推理 - 比如iPad上的所有方向(不包括分屏或滑出时使用)目前正常尺寸。我的应用程序需要将UISlider控件从底部(纵向)移动到右侧(横向),以最大化我的GLKView的屏幕空间。这意味着代码至少有一些东西(方向变化和超视角界限)。由于IB无法在设计时处理代码,因此我决定将所有子视图移动到代码中并消除IB。我对Xcode 8充满希望,我可以使用IB,在玩了两个新的IB之后,我意识到它还不值得 - 我需要约束数组来激活/取消基于superview界限。

长话短说:IB运作良好,尽可能多地使用它。但请记住它的局限性,并且在必要时不要害怕放入视图层的代码中。

<强>控制器:

首先,请记住,一旦删除&#34;模型&#34;和&#34;查看&#34;来自事物,一切,左边是&#34;控制器&#34;。

当然。当然!您的视图控制器需要在其视图(和子视图)中显示数据。它还需要处理来自用户的操作,例如按钮按下滑块更改等。但是从数据库中检索数据呢?如何从第三方Web服务中检索价格或税务信息?或者对你来说,如何在UITableView中创建人员列表(联系人?)?

如果你把所有这些都放到你的视图控制器中祝贺!您刚刚了解了UIViewController&#34; cruft&#34;。我们都做到了这一点 - 它是学习Xcode MVC方式的一部分。它是一种科学的东西,也是一种了解什么有效的艺术。 (虽然它主要经历过。)

随着您的应用程序的增长,您肯定会拥有更多的UIViewControllers。您可能还有其他类,如Person,Country等。最终,您将开始创建各种类的扩展,并可能为您的类创建协议。现在,快速提问:你如何保持这些有条理的东西?单独的文件,组,什么?您可能会发现框架目标最有效。 (如果您打算使用Apple的许多应用扩展程序,那么您将会这样做。)

也许比确定你的&#34;模型更重要&#34;在编码之前,你的&#34;控制器&#34;组织。