2017-01-02 7 views
1

Мне нравится применять шаблон проектирования Model-View-Controller в приложении Cocoa (написанный в Swift). Предположим, пример знаменитого человека: приложение должно отображать текстовое поле и кнопку добавления. Имя человека можно поместить в текстовое поле, а затем сохранить в массиве, нажав кнопку добавления (и содержимое массивов может отображаться в виде таблицы). Теперь раскадровка содержит все связанные с View вещи, в то время как класс Person (с именем переменной) представляет собой модельный класс. Контроллер представления будет отвечать за получение отображения данных (например, делегата таблицы и источника данных) и имеет IBAction, который извлекает имя и помещает его где-нибудь. Но я не уверен, где на самом деле поставить массив, содержащий все имена. Будет ли у меня это и в контроллере представления (что было бы самым простым решением, которое я думаю)? Или где-то еще? Что делать, если приложение становится все более и более сложным с несколькими структурами хранения данных в разных представлениях (с разными контроллерами представлений)?MVC: Где хранить данные?

+0

В реальном проекте вам необходимо сохранить этот массив в некоторой базе данных, локальной или в какой-либо удаленной базе данных, в этой ситуации у вас может быть Служба, которая отвечает за сохранение модели или извлечение ее из базы данных. поэтому любой ViewController будет использовать этот ServiceClass. –

+0

Если я правильно понимаю, вы описываете ответ @bubuxu, но с некоторыми возможностями сохранения/записи (либо на диск, либо на базу данных). Это означает, что данные должны быть загружены/сохранены, когда какой-либо контроллер просмотра хочет получить к нему доступ. Не будет ли это дорогостоящим вычислительным процессом, особенно когда есть много данных для обработки? – DaPhil

ответ

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? 
} 
+0

Итак, вы в основном говорите, имеете дополнительный класс, который содержит массив и предоставляет методы доступа. Но не является ли это неблагоприятным, если у меня есть несколько представлений, в которых мне нравится обращаться к данным, потому что я добавляю данные только к одному конкретному экземпляру ViewModel? – DaPhil

+0

Я хотел бы иметь набор классов для шаблона MVC (или MVVM): Model - ViewModel - View - Контроллер, как вы можете видеть мой образец, есть модели, модели просмотра, представления и классы контроллеров. – bubuxu

0

Модель:

Вы хотите, базу данных или основных данных ,

Я отделяю CD, потому что в некоторых уголках ИТ он считается скорее «моделью» с базой данных mySQL или XML-файлом, сидящим за ней. Как и все открытое для обсуждения, у CD есть свои сильные и слабые стороны. Многие считают, что одна из самых слабых сторон будет расширяться после внедрения.

Что делать, если приложение становится все более и более сложным с несколькими структурами хранения данных в разных представлениях (с разными диспетчерами)?

Для меня это ключевая вещь для модели, а это означает простую базу данных SQL (или реляционной). Если вы не знаете, что я имею в виду по реляционным отношениям, посмотрите на это, потратьте несколько дней на изучение этого. (Подсказка: вы уже там, когда говорите «класс человека». Модель (см., Что я там сделал?), Ваши классы соответствуют - по именам, типам и свойствам - ваши таблицы базы данных. Чем ближе к 1: 1 вы можете делать лучше,

Но имейте в виду масштабируемость и уровни (Model, View, Controller). У Swift есть рассчитанные свойства. Если вы запрашиваете что-то вроде «сколько людей живет в Европе», вам лучше всего использовать SQL - это хранит данные, проходящие через очиститель труб, и работает лучше. Но если вы хотите отобразить что-то вроде «сколько дней до дня рождения Джона Доу», вам, вероятно, лучше всего сделать это либо вычисленное свойство, либо вызываемую функцию на стороне контроллера

Вы также хотите выбрать локальный или облачный. У Facebook, очевидно, есть база данных позади это в облаке. Но мое приложение стороннего подкаста (а не Overcast BTW) имеет локальную базу данных.

Вид:

Вы, кажется, имеют хорошую ручку на этом. Xcode делает хорошую работу, чтобы придерживаться MVC по большей части. Если вы можете полностью придерживаться интерфейса Builder, то у вас уже есть это.

Но некоторые кодеры (как и я) не могут этого сделать. Для всех Apple отлично справляется с ограничениями автоматической компоновки, они принимают некоторые решения, которые я не причастен к рассуждениям - как и все ориентации на iPad (не включая, когда используется разделенный экран или слайд-выход), в настоящий момент нормальный размер. Моему приложению нужно переместить элементы управления UISlider снизу (портрет) вправо (пейзаж), чтобы увеличить пространство экрана для моего GLKView. Это означает, что код, по крайней мере, некоторые вещи (изменения ориентации и ограничения супервизора). И поскольку IB не может обработать код во время разработки, я решил переместить все подзадачи в код и устранить IB. Я надеялся на Xcode 8, что я мог бы использовать IB, и после месяца игры с новым материалом IB я понял, что это еще не стоит - мне нужны массивы ограничений для активации/деактивации на основе ограничений супервизора.

Короче говоря: IB работает хорошо, используйте его как можно больше. Но помните, что это ограничения, и не бойтесь входить в код для своего слоя просмотра, когда это необходимо.

Контроллер:

Во-первых, имейте в виду, что, как только вы удалите «модель» и «вид» из вещей, все, что осталось «контроллер».

Конечно. Конечно! Контроллеру вашего представления необходимо представить данные в его представлении (и в представлении). Он также должен обрабатывать действия от пользователя, как изменения слайдера кнопок, и т. Д. Но как насчет извлечения данных из базы данных? Как получить информацию о ценах или налогах со стороннего веб-сервиса? Или для вас, как насчет воссоздания списка людей (контактов?) В UITableView?

Если вы положите все это в свой комментарий, диспетчер поздравляет! Вы только что узнали о UIViewController "cruft". Мы все это сделали - все это часть изучения способа Xcode MVC. Это что-то вроде науки, и что-то вроде искусства, чтобы знать, что работает. (Это в основном опыт.)

По мере роста вашего приложения у вас наверняка будет больше UIViewControllers. Вероятно, у вас будут другие классы, такие как Person, Country и т. Д. В конце концов вы начнете создавать расширения для разных классов и, возможно, создавать протоколы для своих классов. Теперь, быстрый вопрос: как вы держите эти вещи организованными? Разделяйте файлы, группы, что? Вы можете дойти до того, что обнаружите, что цель рамок работает лучше всего. (И если вы планируете использовать многие расширения приложений Apple, вы будете.)

Возможно, более важно, чем прибивать вашу «модель» до того, как кодирование прибивает вашу организацию «контроллера».

Смежные вопросы