0Pricing
Swift Academy · Урок

Шаблон MVVM

Разделяйте ответственность представления, модели представления и модели.

«Шаблон MVVM» — бесплатный урок Swift Academy на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Swift Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Swift Academy содержит 4 уроков всего.

Что такое MVVM

MVVM — это сокращение от модель–представление–ViewModel. Это архитектурный шаблон, который разделяет приложение на три слоя, каждый из которых отвечает за свою чётко определённую задачу.

  • Модель — данные и бизнес-правила
  • Представление — то, что видит пользователь
  • ViewModel — связующее звено, подготавливающее данные модели для представления

Цель такого подхода — разделение обязанностей: каждый слой изменяется по собственной причине, независимо от остальных.

Слой модели

Модель хранит исходные данные и правила, которые ими управляют. Она ничего не знает об экране и способе отображения данных.

Модели обычно представляют собой простые структуры или объекты предметной области. Их легко тестировать, поскольку у них нет зависимостей от пользовательского интерфейса.

struct User {
    let id: UUID
    let firstName: String
    let lastName: String
    let isPremium: Bool
}

struct Order {
    let items: [String]
    let total: Decimal
}

Слой представления

Представление отвечает только за отображение. В SwiftUI это структуры View, а в UIKit — UIViewController и его дочерние представления.

Хорошее представление не содержит бизнес-логики. Оно лишь отображает state и передаёт действия пользователя в ViewModel.

struct ProfileView: View {
    @StateObject var viewModel: ProfileViewModel

    var body: some View {
        VStack {
            Text(viewModel.displayName)
            if viewModel.showBadge {
                Text("Premium")
            }
        }
    }
}

Слой ViewModel

ViewModel находится между моделью и представлением. Он получает исходные данные модели и преобразует их в значения, готовые к отображению, которые представление может показывать напрямую.

Он также предоставляет намерения (методы), которые представление вызывает при взаимодействии с пользователем.

final class ProfileViewModel: ObservableObject {
    @Published var displayName: String
    @Published var showBadge: Bool

    init(user: User) {
        displayName = user.firstName + " " + user.lastName
        showBadge = user.isPremium
    }
}

Зачем разделять обязанности

Когда форматирование, сетевое взаимодействие и отображение смешаны внутри контроллера представления, этот файл превращается в огромный фрагмент, который невозможно тестировать.

Разделение обязанностей позволяет:

  • повторно использовать модель на разных экранах;
  • тестировать ViewModel модульными тестами без пользовательского интерфейса;
  • сохранить представление небольшим и декларативным.

Что относится к модели

В модель помещают:

  • сущности предметной области (User, Product);
  • правила бизнес-валидации;
  • абстракции хранения данных и сетевого взаимодействия, часто реализованные через службы, которые вызывает ViewModel.

Никогда не помещайте в модель строки интерфейса, цвета или форматирование.

Что относится к ViewModel

ViewModel отвечает за логику представления:

  • преобразует даты, валюты и имена в строки для отображения;
  • определяет, какие состояния интерфейса видны пользователю: загрузка, ошибка или отсутствие данных;
  • координирует вызовы служб и предоставляет результаты.
final class CartViewModel: ObservableObject {
    @Published var totalText: String = ""

    func update(with order: Order) {
        let formatter = NumberFormatter()
        formatter.numberStyle = .currency
        totalText = formatter.string(from: order.total as NSNumber) ?? "-"
    }
}

Что относится к представлению

Представление должно только:

  • размещать и отображать элементы интерфейса;
  • читать опубликованный state из ViewModel;
  • передавать нажатия и жесты, вызывая методы ViewModel.

Если внутри представления вы обнаружили if, определяющий бизнес-правила, скорее всего, эту логику следует поместить в ViewModel.

Поток данных в MVVM

Данные движутся в одном направлении, а действия — в обратном:

  • Модель -> ViewModel -> Представление — для данных;
  • Представление -> ViewModel — для намерений пользователя.

Представление никогда не обращается к модели напрямую. Благодаря этому зависимости направлены внутрь, к предметной области.

MVVM и архитектура с контроллером

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

MVVM выносит эту логику представления в ViewModel, оставляя контроллер, а в SwiftUI — представление, тонким. ViewModel не зависит от фреймворка интерфейса, поэтому его гораздо проще тестировать.

Полный фрагмент

Ниже приведён небольшой, но полный фрагмент MVVM, связывающий все слои.

struct Account { let balance: Decimal }

final class AccountViewModel: ObservableObject {
    @Published var balanceText: String
    init(account: Account) {
        balanceText = "$" + "\(account.balance)"
    }
}

struct AccountView: View {
    @StateObject var viewModel: AccountViewModel
    var body: some View { Text(viewModel.balanceText) }
}

Быстрая проверка

Проверьте, насколько хорошо вы понимаете обязанности компонентов MVVM.

Итоги

Вы изучили три слоя MVVM и границы между ними:

  • Модель — исходные данные и бизнес-правила, без пользовательского интерфейса;
  • ViewModel — логика представления и намерения;
  • Представление — только отображение state из ViewModel.

Разделение этих обязанностей делает код тестируемым, пригодным для повторного использования и понятным для анализа. Далее мы свяжем ViewModel с представлением с помощью привязок.

Часто задаваемые вопросы

Урок «Шаблон MVVM» бесплатный?

Да — полный текст урока «Шаблон MVVM» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Swift Academy, подпишись на CoddyKit PRO. Курс Swift Academy содержит 4 уроков всего.

Чему я научусь в уроке «Шаблон MVVM»?

Разделяйте ответственность представления, модели представления и модели. Ты практикуешь Swift Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Swift Academy?

Предыдущий опыт не требуется. Swift Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.

Сколько времени занимает урок «Шаблон MVVM»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Swift Academy?

Да. Каждый урок Swift Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Шаблон MVVM
  2. Связывание моделей представления с представлениями
  3. Шаблон координатора
  4. Тестирование моделей представления
← Назад к Swift Academy