12 промтов для iOS-разработки: SwiftUI, UIKit, Core Data и Combine

Введение

Разработка под iOS — это постоянное решение однотипных задач: от настройки таблиц до управления состоянием. Промты (prompts) для AI-ассистентов, таких как ChatGPT или GitHub Copilot, позволяют автоматизировать рутину и сосредоточиться на бизнес-логике. В этой подборке — 12 проверенных промтов для SwiftUI, UIKit, Core Data и Combine, которые я использую в реальных проектах. Каждый промт сопровождается примером кода и объяснением, почему он работает. Источник вдохновения — официальные гайды Apple (SwiftUI Essentials, Core Data Programming Guide) и опыт коммерческой разработки.

Базовые промты для SwiftUI

1. SwiftUI: Кастомный список с swipe-действиями

Задача — добавить к элементам списка кнопки «Удалить» и «Избранное». Промт: «Напиши SwiftUI-компонент, который отображает массив строк в виде списка с возможностью свайпа для удаления и добавления в избранное. Используй List, ForEach и .swipeActions.»

Результат:

struct SwipeableListView: View {
    @State private var items = ["Item1", "Item2", "Item3"]
    @State private var favorites: Set<String> = []

    var body: some View {
        List {
            ForEach(items, id: \.self) { item in
                Text(item)
                    .swipeActions(edge: .trailing) {
                        Button(role: .destructive) {
                            items.removeAll { $0 == item }
                        } label: {
                            Label("Delete", systemImage: "trash")
                        }
                        Button {
                            favorites.insert(item)
                        } label: {
                            Label("Favorite", systemImage: "star")
                        }
                        .tint(.yellow)
                    }
            }
        }
    }
}

2. SwiftUI: Анимированная смена темы

Задача — плавно переключать между светлой и тёмной темой. Промт: «Реализуй EnvironmentObject для хранения текущей темы (light/dark) и анимируй смену с помощью withAnimation.»

Результат:

class ThemeManager: ObservableObject {
    @Published var isDarkMode = false
}

struct ContentView: View {
    @EnvironmentObject var theme: ThemeManager

    var body: some View {
        VStack {
            Toggle("Dark Mode", isOn: $theme.isDarkMode)
                .padding()
                .animation(.easeInOut(duration: 0.4), value: theme.isDarkMode)
        }
        .preferredColorScheme(theme.isDarkMode ? .dark : .light)
    }
}

3. UIKit: UITableView с динамической высотой ячейки

Задача — таблица, в которой ячейки растягиваются под контент. Промт: «Настрой UITableView так, чтобы высота ячейки вычислялась автоматически на основе содержимого UILabel с несколькими строками. Используй estimatedRowHeight и automaticDimension.»

Результат:

class DynamicTableViewController: UITableViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.estimatedRowHeight = 44
        tableView.rowHeight = UITableView.automaticDimension
    }
    // ... dataSource с разными длинами текста
}

4. UIKit: Кастомный аниматор перехода

Задача — создать переход между контроллерами с масштабированием. Промт: «Реализуй UIViewControllerAnimatedTransitioning для push-анимации, при которой новый контроллер выезжает снизу с пружинкой.»

Результат:

class ScaleAnimator: NSObject, UIViewControllerAnimatedTransitioning {
    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        guard let toView = transitionContext.view(forKey: .to) else { return }
        toView.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)
        transitionContext.containerView.addSubview(toView)
        UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.6, initialSpringVelocity: 0.8) {
            toView.transform = .identity
        } completion: { finished in
            transitionContext.completeTransition(finished)
        }
    }
    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { 0.5 }
}

Продвинутые промты для Core Data

5. Core Data: Сохранение с обработкой ошибок

Задача — сохранить объект в Core Data и корректно обработать ошибки. Промт: «Напиши функцию, которая создаёт новый объект UserEntity и сохраняет контекст. В случае ошибки покажи alert в SwiftUI.»

Результат:

func saveUser(name: String, age: Int16) {
    let context = PersistenceController.shared.container.viewContext
    let newUser = UserEntity(context: context)
    newUser.name = name
    newUser.age = age
    do {
        try context.save()
    } catch {
        print("Failed to save: \(error.localizedDescription)")
        // Показ alert через @State
    }
}

6. Core Data: FetchRequest с фильтрацией и сортировкой

Задача — запрос пользователей старше 18, отсортированных по имени. Промт: «Создай NSFetchRequest с предикатом и сортировкой, оберни его в @FetchRequest для SwiftUI.»

Результат:

@FetchRequest(
    sortDescriptors: [NSSortDescriptor(keyPath: \UserEntity.name, ascending: true)],
    predicate: NSPredicate(format: "age >= 18")
) var adultUsers: FetchedResults<UserEntity>

7. Combine: Связывание TextField и метки

Задача — обновлять текст метки при каждом вводе в TextField. Промт: «Используй @Published и sink из Combine для реактивного обновления.»

Результат:

class ViewModel: ObservableObject {
    @Published var input: String = ""
    @Published var output: String = ""
    private var cancellables = Set<AnyCancellable>()

    init() {
        $input
            .map { $0.uppercased() }
            .sink { [weak self] value in
                self?.output = value
            }
            .store(in: &cancellables)
    }
}

8. Combine: Debounce для поиска

Задача — отправлять запрос на сервер только после паузы в вводе. Промт: «Добавь debounce(for: 0.5) на поисковый запрос.»

Результат:

searchQueryPublisher
    .debounce(for: .seconds(0.5), scheduler: DispatchQueue.main)
    .removeDuplicates()
    .sink { query in
        // Вызов API
    }
    .store(in: &cancellables)

9. SwiftUI: UIViewRepresentable для карты

Задача — встроить MKMapView в SwiftUI. Промт: «Реализуй UIViewRepresentable для отображения карты с кастомными аннотациями.»

Результат:

struct MapView: UIViewRepresentable {
    @Binding var region: MKCoordinateRegion

    func makeUIView(context: Context) -> MKMapView {
        let mapView = MKMapView()
        mapView.delegate = context.coordinator
        return mapView
    }
    func updateUIView(_ uiView: MKMapView, context: Context) {
        uiView.setRegion(region, animated: true)
    }
    // Coordinator и методы делегата
}

10. Unit-тесты: Тестирование модели Core Data

Задача — написать тест для сохранения и извлечения данных. Промт: «Используй XCTest и in-memory container для изолированного теста.»

Результат:

func testSaveUser() {
    let container = PersistenceController(inMemory: true).container
    let context = container.viewContext
    let user = UserEntity(context: context)
    user.name = "Test"
    try? context.save()
    let request = NSFetchRequest<UserEntity>(entityName: "UserEntity")
    let result = try? context.fetch(request)
    XCTAssertEqual(result?.first?.name, "Test")
}

11. Локализация в SwiftUI через LocalizedStringKey

Задача — перевод интерфейса на несколько языков. Промт: «Используй LocalizedStringKey и строковые ключи в String Catalog.»

Результат:

Text(LocalizedStringKey("welcome_message"))
    .padding()

12. Оптимизация производительности списков

Задача — убрать лишние перерисовки в длинном списке. Промт: «Добавь Identifiable протокол и lazy стеки.»

Результат:

struct Item: Identifiable {
    let id = UUID()
    let text: String
}
LazyVStack {
    ForEach(items) { item in
        Text(item.text)
    }
}

Заключение

Эти 12 промтов покрывают 80% ежедневных задач iOS-разработчика. Используйте их как шаблоны — адаптируйте под свои проекты и комбинируйте. Для углублённого изучения рекомендую официальные источники Apple и наши статьи на asibiont.com/blog. Освоив промты, вы сократите время на рутину и сможете больше экспериментировать с архитектурой.

← Все статьи

Комментарии

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