iOS Mobile Инженер

iOS Mobile Инженер

Роадмап навыков для прокачки

Модификатор alert

SwiftUINavigationAlerts & Confirmations

Основная идея

Модификатор .alert() показывает системное диалоговое окно с заголовком, сообщением и кнопками действий. Alerts используются для важных уведомлений и подтверждения действий.

Ключевые аспекты

  • alert(isPresented:) — показ по Bool условию
  • alert(item:) — показ для конкретного item (Identifiable)
  • Кнопки действий — определяются через замыкание
  • role: .destructive — красная кнопка удаления
  • role: .cancel — кнопка отмены

Плюсы

  • Системный внешний вид
  • Простой синтаксис
  • Автоматическая accessibility
  • Поддержка нескольких кнопок

Минусы

  • Ограниченная кастомизация дизайна
  • Нельзя добавить TextField напрямую (нужен alert с TextFieldAlert в iOS 15+)
  • Максимум 2-3 кнопки по guidelines

Частые ошибки на собеседованиях

  • Пытаются кастомизировать внешний вид alert (нельзя)
  • Забывают про role: .cancel и role: .destructive
  • Путают alert и confirmationDialog
  • Не используют LocalizedStringKey для локализации

Введение и проблематика

Alerts (диалоговые окна) используются для важных уведомлений и подтверждения критических действий. В SwiftUI alerts создаются модификатором .alert().

Alert — это системный UI-элемент. Его нельзя стилизовать, но он автоматически адаптируется под тему устройства и accessibility настройки.


Базовая теория

Базовый alert

Code Example 1: Как создать простой alert?

swift
struct SimpleAlertView: View {
    @State private var showingAlert = false
 
    var body: some View {
        Button("Показать Alert") {
            showingAlert = true
        }
        .alert("Заголовок", isPresented: $showingAlert) {
            Button("OK") { }
        } message: {
            Text("Это сообщение alert")
        }
    }
}

Структура alert (iOS 15+)

swift
.alert(
    "Заголовок",              // Title
    isPresented: $showAlert   // Binding<Bool>
) {
    // Кнопки действий
    Button("OK") { }
} message: {
    // Опциональное сообщение
    Text("Описание")
}

Практические примеры

Alert с несколькими кнопками

Code Example 2: Как добавить кнопки с разными действиями?

swift
struct MultiButtonAlert: View {
    @State private var showingAlert = false
 
    var body: some View {
        Button("Удалить элемент") {
            showingAlert = true
        }
        .alert("Удалить?", isPresented: $showingAlert) {
            Button("Отмена", role: .cancel) { }
            Button("Удалить", role: .destructive) {
                deleteItem()
            }
        } message: {
            Text("Это действие нельзя отменить")
        }
    }
 
    func deleteItem() {
        print("Удалено")
    }
}

Alert с данными (item)

Code Example 3: Как показать alert с информацией об элементе?

swift
struct ItemAlertView: View {
    @State private var itemToDelete: Item?
 
    let items = [
        Item(id: 1, name: "Документ 1"),
        Item(id: 2, name: "Документ 2")
    ]
 
    var body: some View {
        List(items) { item in
            HStack {
                Text(item.name)
                Spacer()
                Button {
                    itemToDelete = item
                } label: {
                    Image(systemName: "trash")
                        .foregroundStyle(.red)
                }
            }
        }
        .alert(
            "Удалить \(itemToDelete?.name ?? "")?",
            isPresented: Binding(
                get: { itemToDelete != nil },
                set: { if !$0 { itemToDelete = nil } }
            )
        ) {
            Button("Отмена", role: .cancel) { }
            Button("Удалить", role: .destructive) {
                if let item = itemToDelete {
                    print("Удаляем: \(item.name)")
                }
            }
        }
    }
}
 
struct Item: Identifiable {
    let id: Int
    let name: String
}

Alert с TextField (iOS 15+)

Code Example 4: Как добавить поле ввода в alert?

swift
struct TextFieldAlert: View {
    @State private var showingAlert = false
    @State private var username = ""
 
    var body: some View {
        Button("Ввести имя") {
            showingAlert = true
        }
        .alert("Введите имя", isPresented: $showingAlert) {
            TextField("Имя пользователя", text: $username)
            Button("Отмена", role: .cancel) { }
            Button("Сохранить") {
                print("Сохранено: \(username)")
            }
        } message: {
            Text("Введите ваше имя для отображения в профиле")
        }
    }
}

Пограничные кейсы

Alert vs ConfirmationDialog

Code Example 5: Когда использовать alert, а когда confirmationDialog?

swift
struct DialogComparison: View {
    @State private var showAlert = false
    @State private var showDialog = false
 
    var body: some View {
        VStack(spacing: 20) {
            // Alert — для важных уведомлений
            Button("Alert") { showAlert = true }
                .alert("Ошибка сети", isPresented: $showAlert) {
                    Button("OK") { }
                } message: {
                    Text("Проверьте подключение к интернету")
                }
 
            // ConfirmationDialog — для выбора действия
            Button("Действия") { showDialog = true }
                .confirmationDialog("Выберите действие", isPresented: $showDialog) {
                    Button("Поделиться") { }
                    Button("Скопировать") { }
                    Button("Удалить", role: .destructive) { }
                    Button("Отмена", role: .cancel) { }
                }
        }
    }
}

Roles кнопок

swift
.alert("Действие", isPresented: $showAlert) {
    Button("Обычная") { }               // Синяя
    Button("Деструктивная", role: .destructive) { }  // Красная
    Button("Отмена", role: .cancel) { }    // Жирная, внизу
}

Плюсы и минусы

АспектОписание
Системный вид✅ Консистентный с iOS
Accessibility✅ Автоматическая поддержка
Кастомизация❌ Нельзя менять дизайн
TextField⚠️ Только с iOS 15+

Вопросы интервьюера

Q: Чем alert отличается от confirmationDialog?

Alert — для уведомлений и простых подтверждений. ConfirmationDialog — для выбора действия из списка, появляется снизу экрана.

Q: Как добавить TextField в alert?

С iOS 15+ можно добавить TextField внутри блока кнопок: .alert { TextField(...); Button(...) }.

Q: Что делает role: .destructive?

Окрашивает кнопку в красный цвет, сигнализируя о деструктивном действии.

Q: Можно ли показать alert без кнопок?

Нет, alert требует хотя бы одну кнопку для закрытия.


Источники

Code Example 1: Simple alert

❓ Как создать простой alert?

swift
struct SimpleAlertView: View {
    @State private var showingAlert = false
 
    var body: some View {
        Button("Показать Alert") {
            showingAlert = true
        }
        .alert("Заголовок", isPresented: $showingAlert) {
            Button("OK") { }
        } message: {
            Text("Это сообщение alert")
        }
    }
}

Code Example 2: Multi-button alert

❓ Как добавить кнопки с разными действиями?

swift
struct MultiButtonAlert: View {
    @State private var showingAlert = false
 
    var body: some View {
        Button("Удалить элемент") {
            showingAlert = true
        }
        .alert("Удалить?", isPresented: $showingAlert) {
            Button("Отмена", role: .cancel) { }
            Button("Удалить", role: .destructive) {
                deleteItem()
            }
        } message: {
            Text("Это действие нельзя отменить")
        }
    }
 
    func deleteItem() {
        print("Удалено")
    }
}

Code Example 3: Alert with item data

❓ Как показать alert с информацией об элементе?

swift
struct ItemAlertView: View {
    @State private var itemToDelete: Item?
 
    var body: some View {
        Button("Удалить") {
            itemToDelete = Item(id: 1, name: "Документ")
        }
        .alert(
            "Удалить \(itemToDelete?.name ?? "")?",
            isPresented: Binding(
                get: { itemToDelete != nil },
                set: { if !$0 { itemToDelete = nil } }
            )
        ) {
            Button("Отмена", role: .cancel) { }
            Button("Удалить", role: .destructive) { }
        }
    }
}

Code Example 4: Alert with TextField

❓ Как добавить поле ввода в alert?

swift
struct TextFieldAlert: View {
    @State private var showingAlert = false
    @State private var username = ""
 
    var body: some View {
        Button("Ввести имя") {
            showingAlert = true
        }
        .alert("Введите имя", isPresented: $showingAlert) {
            TextField("Имя пользователя", text: $username)
            Button("Отмена", role: .cancel) { }
            Button("Сохранить") { }
        }
    }
}

Code Example 5: Alert vs ConfirmationDialog

❓ Когда использовать alert, а когда confirmationDialog?

swift
struct DialogComparison: View {
    @State private var showAlert = false
    @State private var showDialog = false
 
    var body: some View {
        VStack(spacing: 20) {
            Button("Alert") { showAlert = true }
                .alert("Ошибка сети", isPresented: $showAlert) {
                    Button("OK") { }
                }
 
            Button("Действия") { showDialog = true }
                .confirmationDialog("Выберите", isPresented: $showDialog) {
                    Button("Поделиться") { }
                    Button("Удалить", role: .destructive) { }
                    Button("Отмена", role: .cancel) { }
                }
        }
    }
}