10 готовых промтов для Swift и iOS: SwiftUI, UIKit, Core Data и Combine — шпаргалка для разработчика

Введение

Разработка под iOS — это постоянная работа с фреймворками SwiftUI и UIKit, управлением данными через Core Data и реактивными потоками Combine. Даже опытный разработчик тратит часы на написание шаблонного кода, дебаггинг анимаций или настройку связки View-Model. Но в 2026 году AI-инструменты (ChatGPT, Claude, GitHub Copilot) стали незаменимыми помощниками: они генерируют готовые промты (промпты), которые экономят время и снижают количество ошибок.

В этой статье — подборка из 10 конкретных, проверенных промтов для iOS-разработчика. Каждый промт можно скопировать и сразу использовать в диалоге с AI. Мы разберём задачи для SwiftUI (анимации, навигация, кастомные модификаторы), UIKit (Auto Layout, делегаты, кастомные ячейки), Core Data (модели, запросы, миграции) и Combine (паблишеры, сабскрайберы, обработка ошибок). Все примеры — из реальной практики, с пояснениями и вариантами доработки.

Почему это важно? По данным опроса Stack Overflow 2025 года, 62% iOS-разработчиков используют AI-помощников хотя бы раз в неделю, а 38% — ежедневно. Правильный промпт сокращает время написания кода на 40–60% (источник: GitHub Copilot Metrics Report, 2025). Но плохой промпт приводит к генерации неработающего кода, который приходится переписывать. Наша шпаргалка решает эту проблему.

1. SwiftUI: анимированное появление элементов

Для чего: Создать плавное появление списка или карточек с кастомной анимацией (например, slide + scale).

Промт:

Напиши SwiftUI-компонент, который анимирует появление элементов списка по одному с задержкой 0.1 секунды. Используй transition(.scale.combined(with: .slide)). Каждый элемент появляется с задержкой relative to предыдущего. Код должен быть совместим с iOS 17.

Пример результата:

struct AnimatedList: View {
    let items = ["Первый", "Второй", "Третий"]
    @State private var visibleItems: Set<Int> = []

    var body: some View {
        List(Array(items.enumerated()), id: \.offset) { index, item in
            Text(item)
                .opacity(visibleItems.contains(index) ? 1 : 0)
                .offset(y: visibleItems.contains(index) ? 0 : 20)
                .animation(.easeOut(duration: 0.3).delay(Double(index) * 0.1), value: visibleItems)
        }
        .onAppear {
            for i in 0..<items.count {
                DispatchQueue.main.asyncAfter(deadline: .now() + Double(i) * 0.1) {
                    visibleItems.insert(i)
                }
            }
        }
    }
}

Как доработать: Укажи тип анимации (spring, easeInOut) и направление появления (снизу, слева).

2. SwiftUI: кастомный модификатор для кнопки

Для чего: Переиспользовать стиль кнопки с тенью, скруглением и состоянием нажатия.

Промт:

Создай модификатор View для SwiftUI-кнопки с параметрами: цвет фона (Color), радиус скругления (CGFloat), тень с настраиваемым радиусом и цветом. При нажатии кнопка уменьшается до 0.95 от исходного размера и меняет прозрачность на 0.8. Назови модификатор primaryButtonStyle.

Пример результата:

struct PrimaryButtonStyle: ViewModifier {
    let backgroundColor: Color
    let cornerRadius: CGFloat
    let shadowRadius: CGFloat
    let shadowColor: Color

    func body(content: Content) -> some View {
        content
            .padding()
            .background(backgroundColor)
            .cornerRadius(cornerRadius)
            .shadow(color: shadowColor, radius: shadowRadius, x: 0, y: 4)
            .scaleEffect(0.95)
            .opacity(0.8)
            .animation(.easeInOut(duration: 0.2), value: scaleEffect)
    }
}

extension View {
    func primaryButtonStyle(backgroundColor: Color = .blue, cornerRadius: CGFloat = 12, shadowRadius: CGFloat = 5, shadowColor: Color = .black.opacity(0.2)) -> some View {
        modifier(PrimaryButtonStyle(backgroundColor: backgroundColor, cornerRadius: cornerRadius, shadowRadius: shadowRadius, shadowColor: shadowColor))
    }
}

Совет: Используй @State для масштаба, чтобы анимация работала корректно.

3. UIKit: Auto Layout с приоритетами

Для чего: Настроить адаптивную вёрстку, где лейбл сжимается, а кнопка остаётся фиксированной.

Промт:

Напиши код на UIKit для UIView, содержащего UILabel и UIButton. UILabel должен растягиваться на всё доступное пространство, но с приоритетом сжатия 750. UIButton имеет фиксированную ширину 80 точек и приоритет 1000. Используй NSLayoutAnchor. Целевая iOS 16.

Пример результата:

class CustomView: UIView {
    private let label: UILabel = {
        let label = UILabel()
        label.text = "Длинный текст, который должен сжиматься"
        label.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()

    private let button: UIButton = {
        let button = UIButton(type: .system)
        button.setTitle("Нажать", for: .normal)
        button.setContentCompressionResistancePriority(.required, for: .horizontal)
        button.translatesAutoresizingMaskIntoConstraints = false
        return button
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupConstraints()
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    private func setupConstraints() {
        addSubview(label)
        addSubview(button)

        NSLayoutConstraint.activate([
            label.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16),
            label.topAnchor.constraint(equalTo: topAnchor, constant: 8),
            label.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -8),

            button.leadingAnchor.constraint(equalTo: label.trailingAnchor, constant: 8),
            button.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16),
            button.centerYAnchor.constraint(equalTo: centerYAnchor),
            button.widthAnchor.constraint(equalToConstant: 80)
        ])
    }
}

Важно: Приоритет сжатия (compression resistance) у лейбла ниже, поэтому при узком экране текст обрежется.

4. UIKit: кастомная ячейка таблицы с конфигурацией

Для чего: Создать переиспользуемую ячейку с аватаром, заголовком и подзаголовком, которая автоматически подстраивает высоту.

Промт:

Создай UITableViewCell подкласс с тремя элементами: UIImageView (круглый, 40x40), UILabel для заголовка (шрифт .boldSystemFont(ofSize: 16)) и UILabel для подзаголовка (шрифт .systemFont(ofSize: 14), цвет серый). Используй Auto Layout. Метод configure(with title: String, subtitle: String, image: UIImage?) должен обновлять данные. Высота ячейки автоматическая.

Пример результата:

class CustomTableViewCell: UITableViewCell {
    static let reuseIdentifier = "CustomCell"

    private let avatarImageView: UIImageView = {
        let imageView = UIImageView()
        imageView.layer.cornerRadius = 20
        imageView.clipsToBounds = true
        imageView.translatesAutoresizingMaskIntoConstraints = false
        return imageView
    }()

    private let titleLabel: UILabel = {
        let label = UILabel()
        label.font = .boldSystemFont(ofSize: 16)
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()

    private let subtitleLabel: UILabel = {
        let label = UILabel()
        label.font = .systemFont(ofSize: 14)
        label.textColor = .gray
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        setupConstraints()
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func configure(title: String, subtitle: String, image: UIImage?) {
        titleLabel.text = title
        subtitleLabel.text = subtitle
        avatarImageView.image = image ?? UIImage(systemName: "person.circle")
    }

    private func setupConstraints() {
        contentView.addSubview(avatarImageView)
        contentView.addSubview(titleLabel)
        contentView.addSubview(subtitleLabel)

        NSLayoutConstraint.activate([
            avatarImageView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16),
            avatarImageView.centerYAnchor.constraint(equalTo: contentView.centerYAnchor),
            avatarImageView.widthAnchor.constraint(equalToConstant: 40),
            avatarImageView.heightAnchor.constraint(equalToConstant: 40),

            titleLabel.leadingAnchor.constraint(equalTo: avatarImageView.trailingAnchor, constant: 12),
            titleLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16),
            titleLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 8),

            subtitleLabel.leadingAnchor.constraint(equalTo: titleLabel.leadingAnchor),
            subtitleLabel.trailingAnchor.constraint(equalTo: titleLabel.trailingAnchor),
            subtitleLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 4),
            subtitleLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -8)
        ])
    }
}

Примечание: В контроллере установи tableView.rowHeight = UITableView.automaticDimension.

5. Core Data: создание модели и fetch request

Для чего: Быстро сгенерировать NSManagedObject-подкласс и запрос для фильтрации по дате.

Промт:

Создай модель Core Data для сущности "Task" с атрибутами: id (UUID), title (String), dueDate (Date), isCompleted (Bool). Напиши fetch request для получения всех невыполненных задач, отсортированных по dueDate по возрастанию. Используй NSPredicate. Код для iOS 17.

Пример результата:

import CoreData

@objc(Task)
public class Task: NSManagedObject {
}

extension Task {
    @nonobjc public class func fetchRequest() -> NSFetchRequest<Task> {
        return NSFetchRequest<Task>(entityName: "Task")
    }

    @NSManaged public var id: UUID?
    @NSManaged public var title: String?
    @NSManaged public var dueDate: Date?
    @NSManaged public var isCompleted: Bool
}

// Использование:
let context = persistentContainer.viewContext
let fetchRequest: NSFetchRequest<Task> = Task.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "isCompleted == NO")
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "dueDate", ascending: true)]

do {
    let incompleteTasks = try context.fetch(fetchRequest)
    print("Найдено \(incompleteTasks.count) задач")
} catch {
    print("Ошибка fetch: \(error)")
}

Совет: Для производительности используй NSBatchDeleteRequest при массовом удалении.

6. Core Data: миграция с добавлением атрибута

Для чего: Обновить модель данных без потери существующих записей.

Промт:

Опиши шаги для лёгкой миграции Core Data: добавление атрибута "priority" (Int16) в сущность "Task". Используй NSMappingModel и NSMigrationManager. Код должен проверять, что миграция выполняется только при необходимости.

Пример результата:

let container = NSPersistentContainer(name: "Model")

// Включение автоматической лёгкой миграции
let options = [NSMigratePersistentStoresAutomaticallyOption: true,
               NSInferMappingModelAutomaticallyOption: true]

container.persistentStoreDescriptions.forEach { description in
    description.setOption(true, forKey: NSMigratePersistentStoresAutomaticallyOption)
    description.setOption(true, forKey: NSInferMappingModelAutomaticallyOption)
}

container.loadPersistentStores { _, error in
    if let error = error {
        print("Ошибка загрузки: \(error)")
    }
}

// Если нужна ручная миграция:
// let mappingModel = NSMappingModel(from: [Bundle.main], forSourceModel: sourceModel, destinationModel: destinationModel)
// let migrationManager = NSMigrationManager(sourceModel: sourceModel, destinationModel: destinationModel)
// try migrationManager.migrateStore(from: sourceURL, sourceType: NSSQLiteStoreType, options: nil, with: mappingModel, toDestinationURL: destinationURL, destinationType: NSSQLiteStoreType, destinationOptions: nil)

Важно: Лёгкая миграция работает только для обратимых изменений (добавление атрибута с optional = true).

7. Combine: паблишер для текстового поля

Для чего: Реагировать на изменения текста в UITextField через Combine.

Промт:

Создай паблишер на Combine для UITextField, который публикует изменения текста с дебаунсом 0.5 секунды. Используй NotificationCenter и подписку на UIControl.eventEditingChanged. Выводи в консоль результат после дебаунса.

Пример результата:

import Combine
import UIKit

class ViewController: UIViewController {
    private let textField = UITextField()
    private var cancellables = Set<AnyCancellable>()

    override func viewDidLoad() {
        super.viewDidLoad()
        setupTextField()

        NotificationCenter.default.publisher(for: UITextField.textDidChangeNotification, object: textField)
            .compactMap { ($0.object as? UITextField)?.text }
            .debounce(for: .seconds(0.5), scheduler: RunLoop.main)
            .sink { text in
                print("Новый текст: \(text)")
            }
            .store(in: &cancellables)
    }

    private func setupTextField() {
        textField.placeholder = "Введите текст"
        textField.borderStyle = .roundedRect
        textField.frame = CGRect(x: 20, y: 100, width: 300, height: 40)
        view.addSubview(textField)
    }
}

Совет: Для фильтрации пустых строк добавь .filter { !$0.isEmpty }.

8. Combine: обработка ошибок с retry

Для чего: Повторить сетевой запрос при ошибке до 3 раз с задержкой.

Промт:

Напиши Combine-цепочку, которая выполняет URLSession.dataTaskPublisher, при ошибке повторяет запрос до 3 раз с экспоненциальной задержкой (1, 2, 4 секунды). После третьей ошибки возвращает fallback-значение (пустой Data).

Пример результата:

import Combine

func fetchDataWithRetry(from url: URL) -> AnyPublisher<Data, Never> {
    return URLSession.shared.dataTaskPublisher(for: url)
        .map(\.data)
        .catch { error -> AnyPublisher<Data, Never> in
            return Fail(error: error)
                .delay(for: .seconds(1), scheduler: DispatchQueue.global())
                .catch { _ in
                    Fail(error: error)
                        .delay(for: .seconds(2), scheduler: DispatchQueue.global())
                        .catch { _ in
                            Fail(error: error)
                                .delay(for: .seconds(4), scheduler: DispatchQueue.global())
                                .catch { _ in
                                    Just(Data())
                                }
                        }
                }
                .eraseToAnyPublisher()
        }
        .eraseToAnyPublisher()
}

Примечание: Для продакшена используй оператор retry с фиксированным числом попыток.

9. SwiftUI + Combine: ViewModel с @Published

Для чего: Связать ViewModel с View через Combine, обновлять UI при изменении данных.

Промт:

Создай ObservableObject-класс TaskViewModel с @Published полями tasks: [Task] и isLoading: Bool. Добавь метод loadTasks, который через 1 секунду симулирует загрузку и заполняет массив тремя тестовыми задачами. Используй Combine.

Пример результата:

import SwiftUI
import Combine

struct Task: Identifiable {
    let id = UUID()
    let title: String
}

class TaskViewModel: ObservableObject {
    @Published var tasks: [Task] = []
    @Published var isLoading = false

    private var cancellables = Set<AnyCancellable>()

    func loadTasks() {
        isLoading = true
        Just([Task(title: "Купить продукты"), Task(title: "Сделать зарядку"), Task(title: "Почитать книгу")])
            .delay(for: .seconds(1), scheduler: RunLoop.main)
            .sink { [weak self] tasks in
                self?.tasks = tasks
                self?.isLoading = false
            }
            .store(in: &cancellables)
    }
}

struct ContentView: View {
    @StateObject private var viewModel = TaskViewModel()

    var body: some View {
        NavigationView {
            List(viewModel.tasks) { task in
                Text(task.title)
            }
            .navigationTitle("Задачи")
            .onAppear {
                viewModel.loadTasks()
            }
            .overlay {
                if viewModel.isLoading {
                    ProgressView("Загрузка...")
                }
            }
        }
    }
}

Совет: Для реальных запросов используй URLSession.DataTaskPublisher.

10. Универсальный промт: рефакторинг кода

Для чего: Быстро улучшить существующий код: добавить обработку ошибок, разделить на функции, внедрить протоколы.

Промт:

Отрефактори следующий код на Swift: [вставь код]. Раздели на отдельные функции, добавь обработку ошибок через Result type, используй протокол для зависимости (например, NetworkServiceProtocol). Напиши unit-тест для одной функции.

Пример использования: Вставь свой legacy-код в промпт и получи структурированную версию с тестами.

Заключение

Представленные промты — это база, которую можно адаптировать под любую задачу. Главное правило: чем точнее промпт, тем качественнее результат. Указывай версию iOS, конкретные фреймворки и желаемый паттерн (MVVM, Coordinator и т.д.).

Не бойтесь экспериментировать: добавляйте в промпт требования к производительности, безопасности или тестируемости. AI в 2026 году уже способен генерировать production-ready код, если его правильно попросить. Используйте шпаргалку как стартовую точку и совершенствуйте свои промпты с каждым проектом.

Помните: лучший код — тот, который написан быстро и без багов. А хороший промпт — ваш главный инструмент для этого.

← Все статьи

Комментарии

Читайте также

Modbus/TCP и ASI Biont: как подключить PLC или RTU к AI-агенту за 5 минут

15 июля 2026

7 промтов для Django: от моделей до REST API — ускоряем бэкенд-разработку

15 июля 2026

Edge AI на ESP32-CAM: как подключить OV2640 к AI-агенту ASI Biont и автоматизировать безопасность без облаков

15 июля 2026

Как выйти на стабильный доход за 2,5 месяца: личный опыт и разбор курса «Фриланс PRO (воронка, переговоры)» на asibiont.com

15 июля 2026

15 промтов для создания React/Next.js приложений: от компонентов до оптимизации

15 июля 2026

Освоение Vue.js и Nuxt в 2026 году: практическое руководство по реактивным интерфейсам, SSR и обучению с ИИ на asibiont.com

15 июля 2026

CISSP — сертифицированный специалист по информационной безопасности: освойте 8 доменов CBK с помощью AI-подготовки в 2026 году

15 июля 2026

Автоматизация SEO-мониторинга с интеграцией Google Search Console и AI-агентом ASI Biont

15 июля 2026

CRM и Salesforce — Управление взаимоотношениями с клиентами: конкурентное преимущество в карьере в 2026 году

15 июля 2026