Статьи

Почему MVC не может быть лучшим образцом для приложений какао

MVC означает Model-View-Controller , и это широко распространенный архитектурный шаблон для разработки программного обеспечения. Это фактический шаблон проектирования для разработки Какао, и это было в течение многих, многих лет. Большинство из нас не могут представить себе создание приложений без него. И UIKit (iOS), и AppKit   (macOS) часто используют MVC. Кажется, что у нас нет другого варианта для создания приложений для iOS, tvOS, macOS и watchOS.

Даже если вы не знакомы с шаблоном Model-View-Controller, если у вас есть амбиции по разработке приложений для одной из платформ Apple, вам необходимо узнать, как представления (iOS) и windows (macOS) связаны с контроллерами и какую роль играют модель играет в типичном приложении какао. К счастью, MVC легко изучить.

В этой короткой серии статей я объясню, что такое MVC, как он выглядит в типичном приложении Cocoa и почему он может быть не лучшим решением для разработчиков Cocoa.

Позвольте мне показать вам, как выглядит шаблон MVC в типичном приложении Cocoa. Пример, который я покажу вам, фокусируется на iOS, но все, что мы обсуждаем, относится и к tvOS, macOS и watchOS. Откройте Xcode и создайте новый проект iOS на основе шаблона приложения Single View .

Настройка проекта

Назовите проект MVC и установите « Язык» на « Swift» и « Устройства» на iPhone . Я использую Xcode 8 для этого урока. Параметры конфигурации проекта могут выглядеть немного иначе, если вы используете Xcode 9.

Конфигурирование проекта

Как следует из названия, шаблон Model-View-Controller определяет три компонента, модель , представление и контроллер . Позвольте мне показать вам, где вы можете найти эти компоненты в типичном проекте iOS.

Контроллеры приложения iOS являются контроллерами представления, экземплярами класса UIViewController или его подклассом. Класс UIViewController определен в платформе UIKit . Поскольку мы выбрали шаблон приложения Single View Application при настройке проекта, Xcode создал для нас контроллер для начала, класс ViewController , определенный в ViewController.Swift . Он наследуется от класса UIViewController .

Как следует из названия, экземпляр UIViewController отвечает за управление представлением, экземпляром класса UIView . Каждый контроллер представления в проекте iOS сохраняет сильную ссылку на представление, еще один компонент шаблона Model-View-Controller. Класс UIView также определен в структуре UIKit .

Мы можем найти компонент вида в основной раскадровке проекта. Откройте Main.storyboard в Навигаторе проектов слева и осмотрите Сцена Контроллера Представления . Сцена содержит контроллер представления, экземпляр класса ViewController и управляет экземпляром UIView .

Изучение основной раскадровки проекта

Выберите View в раскадровке слева и откройте Identity Inspector справа. Поле класса представления установлено в UIView . В приложении iOS представления, как правило, являются экземплярами класса UIView UIView или его подкласса.

View является экземпляром класса UIView

До сих пор мы исследовали слой контроллера и слой представления. Но где мы можем найти модельный слой проекта? Модель почти всегда специфична для проекта, над которым вы работаете, и вы должны определить, реализовать и использовать модель проекта. Я пишу модель , но у вас обычно есть несколько моделей, в зависимости от сложности вашего проекта.

Давайте добавим последний кусок головоломки MVC, создав модель. Создайте новый файл Swift и назовите его Person.swift .

Создать новый файл Swift

Выберите Person.swift в Навигаторе проектов слева и определите структуру с именем Person . Мы определяем три свойства:

  • firstName типа String
  • lastName типа String
  • age типа Int
1
2
3
4
5
6
7
struct Person {
 
    let firstName: String
    let lastName: String
    let age: Int
 
}

Теперь у вас есть модель, которую вы можете использовать в своем проекте. Давайте будем проще и определим свойство person типа Person? в классе ViewController . Мы создаем экземпляр Person в viewDidLoad() контроллера представления и присваиваем его свойству person .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
import UIKit
 
class ViewController: UIViewController {
 
    // MARK: — Properties
 
    var person: Person?
 
    // MARK: — View Life Cycle
 
    override func viewDidLoad() {
        super.viewDidLoad()
 
        // Create Person
        person = Person(firstName: «John», lastName: «Doe», age: 40)
    }
 
}

То, что мы видим в этом примере, очень распространено в приложениях Cocoa, работающих на основе шаблона Model-View-Controller. Контроллер представления владеет моделью и управляет ею, а также использует модель для заполнения своего представления. В более сложном приложении вы загружаете данные модели из постоянного хранилища или извлекаете их из удаленного бэкэнда.

Давайте определим выход для экземпляра UILabel в контроллере представления и в основной раскадровке добавим метку к сцене View Controller .

01
02
03
04
05
06
07
08
09
10
11
import UIKit
 
class ViewController: UIViewController {
 
    // MARK: — Properties
 
    @IBOutlet var label: UILabel!
 
    …
 
}
Добавление метки в сцену View Controller

В viewDidLoad() контроллера представления мы безопасно разворачиваем значение, сохраненное в свойстве person и используем его данные для установки свойства UILabel экземпляра UILabel .

01
02
03
04
05
06
07
08
09
10
11
override func viewDidLoad() {
    super.viewDidLoad()
 
    // Create Person
    person = Person(firstName: «John», lastName: «Doe», age: 40)
 
    // Populate Label
    if let person = person {
        label.text = «\(person.lastName), \(person.firstName) (\(person.age))»
    }
}

Результат не очень удивителен, если вы знакомы с разработкой Какао. Это то, что мы в конечном итоге.

MVC в действии

Шаблон Model-View-Controller легко понять и подобрать. Несмотря на его простоту, вы можете найти широкий спектр вкусов MVC. MVC предлагает только базовый проект, который можно изменить на платформе, на которой он используется.

Шаблон Model-View-Controller, с которым вы знакомы в iOS, tvOS, macOS и watchOS, несколько отличается от исходного определения. Хотя различия по сравнению с исходным определением незначительны, они оказывают значительное влияние на код, который вы пишете, а также на удобство сопровождения проекта.

Шаблон Model-View-Controller — это старый шаблон проектирования. Он впервые появился в 1970-х годах в Smalltalk . Шаблон был задуман Тригве Реенскауг . За прошедшие годы модель Model-View-Controller вошла во многие языки и фреймворки, включая Java , Rails и Django .

Ранее я упоминал, что шаблон MVC разбивает приложения на три отдельных компонента: модель , представление и контроллер . Исходная реализация шаблона определяет, что представление отвечает за отображение данных модели для пользователя. Пользователь взаимодействует с приложением через слой представления. Контроллер отвечает за взаимодействие с пользователем и в результате манипулирует данными модели. Представление визуализирует эти изменения для пользователя. Как показано на диаграмме ниже, модель играет ключевую роль в модели MVC, как она была разработана Реенскаугом.

MVC как определено Трюгве Реенскаугом

Реализация, которую мы используем в разработке Какао, отличается от оригинального дизайна Reenskaug. Посмотрите на диаграмму ниже, чтобы лучше понять, что влечет за собой эти различия.

MVC Какао Реализация

Как я упоминал ранее, представление и контроллер имеют близкие отношения. В типичном приложении для iOS контроллер содержит строгую ссылку на представление, которым он управляет. Представление — это тупой объект, который знает, как отображать данные и реагировать на взаимодействие с пользователем. Результат — компонент многократного использования.

Контроллер играет жизненно важную роль в приложениях Cocoa, работающих на основе шаблона Model-View-Controller. Он берет на себя некоторые задачи модели в оригинальной реализации MVC Реенскага. Представление и модель не взаимодействуют напрямую друг с другом. Вместо этого модель обычно принадлежит контроллеру, который он использует для настройки и заполнения представления, которым он управляет.

Я надеюсь, что вы можете увидеть тонкие различия между оригинальной реализацией Reenskaug в Smalltalk и реализацией Cocoa, к которой мы привыкли. Различия незначительны, но, как я сейчас расскажу, их влияние важно.

Прежде чем мы рассмотрим проблемы, которые создает MVC, я хотел бы показать вам, почему шаблон Model-View-Controller стал таким популярным и широко распространенным шаблоном в разработке программного обеспечения. Шаблон Model-View-Controller, который мы используем в разработке Какао, имеет ряд явных преимуществ, которые он унаследовал от первоначальной реализации Reenskaug.

Наиболее очевидным преимуществом модели Model-View-Controller является разделение задач . Например, слой представления отвечает за представление данных пользователю. Уровни модели и контроллера не связаны с представлением данных. Но если вы использовали MVC в проекте Какао, то вы знаете, что это не всегда так. Я расскажу об этом чуть позже.

Непосредственным преимуществом такого разделения интересов является возможность повторного использования . Каждый из компонентов шаблона Model-View-Controller ориентирован на определенную задачу, что означает, что строительные блоки приложения MVC часто легко использовать повторно. Это также позволяет этим компонентам быть слабосвязанными, увеличивая их возможность повторного использования. Это не правда для каждого компонента, хотя. Например, в проекте Какао контроллеры часто являются специфическими для приложения и не являются подходящими кандидатами для повторного использования.

Тем не менее, представления и модели проекта можно использовать многократно, если они спроектированы правильно. Например, представления таблиц и коллекций являются подклассами UIView , которые используются в миллионах приложений. Поскольку табличное представление делегирует взаимодействие пользователя с другим объектом и запрашивает источник данных о данных, которые необходимо отобразить, оно может сосредоточиться исключительно на представлении данных и взаимодействии с пользователем.

Большинство разработчиков быстро понимают, что шаблон Model-View-Controller привносит в таблицу и как он должен быть реализован. К сожалению, модель Model-View-Controller также имеет некрасивую сторону. Я уже писал о возможности повторного использования и разделения проблем. Я уверен, что мне не нужно убеждать вас в этих преимуществах. Табличное представление очень многократно и невероятно эффективно. Разработчики могут использовать стандартные компоненты UIKit в своих приложениях без необходимости создавать подклассы или настраивать их.

Но это только часть истории. Вы знаете, когда начинаете выходить за пределы MVC, когда в ваш проект проникли массивные контроллеры представления. Настало время перемен, когда вы просматриваете сотни или тысячи строк кода, чтобы найти тот метод, который вы ищете.

Большинство разработчиков знают, что входит в уровни представления и модели типичного приложения Cocoa, работающего на основе модели Model-View-Controller. Но какой компонент отвечает за форматирование данных, отображаемых пользователю? Помните, что представления должны быть тупыми и многоразовыми. Представление не должно форматировать данные. Правильно? Следует только знать, как представлять данные и реагировать на взаимодействие с пользователем. Должна ли модель быть связана с форматированием данных?

А как насчет сети? Это, конечно, не задача зрения. Должно ли оно быть делегировано модели? Это не звучит правильно. Почему бы нам не вставить этот кусок кода в контроллер? Это не правильно, но пока подойдет.

После многих строк кода вы получите контроллер, готовый к взрыву, и кошмар для тестирования. Тестирование? Я слышу тебя. Я также не хотел бы тестировать контроллер представления, страдающий синдромом массивного контроллера представления .

Вы начали с благими намерениями, но в итоге вы получили проект с набором избыточных контроллеров, которыми сложно управлять и обслуживать. Вы не ожидаете добавления новых функций в проект, над которым работаете, потому что открытие этих контроллеров представления вызывает у вас тошноту. Это звучит знакомо?

Важно понимать, что это общий сценарий. Многие разработчики выходят за пределы шаблона Model-View-Controller и понимают, что им нужно что-то лучшее. Скорее всего, вы уже рассматривали несколько альтернатив, таких как MVP (Model-View-Presenter) или MVVM (Model-View-ViewModel).

В следующей части этой серии я увеличу шаблон Pattern -View-ViewModel . Будет странно знакомо, если вы уже работали с шаблоном Model-View-Controller. Но шаблон Model-View-ViewModel вносит в таблицу несколько улучшений, которые очень хорошо подходят для разработки Какао.

И пока вы ждете, посмотрите другие наши посты о разработке приложений Какао!

  • стриж
    Что нового в Swift 4
    Патрик Балестра
  • iOS SDK
    Realm Мобильная база данных для iOS
    Дорон Кац
  • iOS SDK
    Ускоренный вход в систему с паролем автозаполнения в iOS 11
    Патрик Балестра