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

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

Привет, коллеги. Если вы пишете под iOS, то знаете, что AI-ассистенты здорово ускоряют рутину — от генерации шаблонов до рефакторинга legacy-кода. Но чтобы получать рабочий код, нужно правильно формулировать промты. Я собрал 12 проверенных шаблонов, которые использую каждый день. Они покрывают четыре ключевые области: SwiftUI, UIKit, Core Data и Combine. В каждом промте — реальный пример и готовый кусок кода.

SwiftUI

Промт #1: Кастомный модификатор анимации

«Напиши SwiftUI модификатор, который добавляет эффект пульсации при появлении view. Используй scaleEffect и opacity с задержкой.»

struct PulseModifier: ViewModifier {
    @State private var animating = false
    func body(content: Content) -> some View {
        content
            .scaleEffect(animating ? 1.1 : 0.9)
            .opacity(animating ? 1 : 0.7)
            .animation(.easeInOut(duration: 1).repeatForever(), value: animating)
            .onAppear { animating = true }
    }
}

Пояснение: модификатор создаёт мягкую пульсацию, что улучшает визуальную обратную связь (например, для кнопок загрузки).

Промт #2: MVVM-структура экрана логина

«Создай SwiftUI View для экрана логина с ViewModel, использующую @Published для полей и валидацию email.»

class LoginViewModel: ObservableObject {
    @Published var email = ""
    @Published var password = ""
    var isValid: Bool { !email.isEmpty && email.contains("@") }
}

struct LoginView: View {
    @StateObject private var vm = LoginViewModel()
    var body: some View {
        VStack {
            TextField("Email", text: $vm.email)
            SecureField("Password", text: $vm.password)
            Button("Login") { }
                .disabled(!vm.isValid)
        }
    }
}

Пояснение: разделение данных и представления упрощает тесты и переиспользование логики.

Промт #3: Список с Pull-to-Refresh

«Реализуй List в SwiftUI с поддержкой pull-to-refresh и асинхронной загрузкой данных через async/await.»

struct RefreshableList: View {
    @State private var items = ["A", "B", "C"]
    var body: some View {
        List(items, id: \.self) { item in
            Text(item)
        }
        .refreshable {
            try? await Task.sleep(nanoseconds: 1_000_000_000)
            items = ["X", "Y", "Z"]
        }
    }
}

Пояснение: .refreshable — встроенный модификатор с iOS 15, элегантно заменяет UIRefreshControl.

UIKit

Промт #4: UITableView с dynamic type

«Создай UITableView с ячейками, поддерживающими Dynamic Type. Используй UIFontMetrics и зарегистрируй ячейку.»

class MyCell: UITableViewCell {
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        textLabel?.font = UIFontMetrics.default.scaledFont(for: UIFont.systemFont(ofSize: 17))
    }
    required init?(coder: NSCoder) { fatalError() }
}

Пояснение: Dynamic Type делает приложение доступным для пользователей с разными настройками шрифта. Подробнее — Apple Human Interface Guidelines.

Промт #5: Кастомный UIControl для рейтинга

«Напиши UIControl — звёздный рейтинг. Используй touchesBegan и sendActions для передачи значения.»

class RatingControl: UIControl {
    var rating = 0 {
        didSet { sendActions(for: .valueChanged) }
    }
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let location = touches.first?.location(in: self) else { return }
        rating = Int(location.x / (bounds.width / 5)) + 1
    }
}

Пояснение: кастомный контрол гибок и легко интегрируется в Interface Builder.

Core Data

Промт #6: Оптимизация NSFetchRequest

«Оптимизируй fetchRequest для большого количества записей: используй batchSize, relationshipKeyPathsForPrefetching и включает подсчёт только количества.»

let request = NSFetchRequest<NSDictionary>(entityName: "Task")
request.resultType = .dictionaryResultType
request.propertiesToFetch = ["title"]
request.predicate = NSPredicate(format: "isCompleted == NO")
request.batchSize = 20

Пояснение: batchSize снижает использование памяти, а dictionaryResultType ускоряет чтение. Документация: Core Data Programming Guide.

Промт #7: Миграция модели версий

«Создай лёгкую миграцию Core Data: добавь атрибут 'updatedAt' в модель версии 2, укажи mapping model и lightweight migration в NSPersistentContainer.»

let container = NSPersistentContainer(name: "Model")
container.persistentStoreDescriptions.first?.shouldMigrateStoreAutomatically = true
container.persistentStoreDescriptions.first?.shouldInferMappingModelAutomatically = true

Пояснение: достаточного двух флагов для автоматической миграции (добавление/удаление атрибутов).

Промт #8: In-memory store для тестов

«Настрой Core Data Stack с NSInMemoryStoreType для unit-тестов, чтобы не трогать реальную базу.»

let container = NSPersistentContainer(name: "Test")
container.persistentStoreDescriptions.first?.url = URL(fileURLWithPath: "/dev/null")
container.persistentStoreDescriptions.first?.type = NSInMemoryStoreType

Пояснение: in-memory store работает быстро и не оставляет следов после тестов.

Combine

Промт #9: Debounced search

«Реализуй поиск с debounce: используй PassthroughSubject, debounce(for: 0.5, scheduler: RunLoop.main) и sink для выполнения запроса.»

let searchSubject = PassthroughSubject<String, Never>()
var cancellables = Set<AnyCancellable>()

searchSubject
    .debounce(for: 0.5, scheduler: RunLoop.main)
    .removeDuplicates()
    .sink { query in
        // API call
    }
    .store(in: &cancellables)

Пояснение: debounce предотвращает лавину запросов при быстром наборе.

Промт #10: Обработка ошибок с catch

«Добавь обработку ошибок в Publisher с помощью catch и возвращай fallback значение.»

URLSession.shared.dataTaskPublisher(for: url)
    .map(\.data)
    .decode(type: [String].self, decoder: JSONDecoder())
    .catch { _ in Just([]) }
    .sink(receiveValue: { items in })

Пояснение: catch перехватывает любую ошибку и заменяет поток на дефолтное значение.

Промт #11: Сочетание Combine с SwiftUI

«Свяжи UITextField с @Published свойством через UIControlPublisher (combine extension).»

extension UITextField {
    var textPublisher: AnyPublisher<String, Never> {
        NotificationCenter.default.publisher(for: UITextField.textDidChangeNotification, object: self)
            .compactMap { ($0.object as? UITextField)?.text }
            .eraseToAnyPublisher()
    }
}

Пояснение: такой publisher позволяет легко интегрировать UIKit в SwiftUI через ObservableObject.

Промт #12: Таймер с автоповтором

«Создай Combine.Timer, который публикует текущее время каждую секунду и обновляет SwiftUI View.»

struct TimerView: View {
    @State private var now = Date()
    let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
    var body: some View {
        Text("\(now)")
            .onReceive(timer) { time in now = time }
    }
}

Пояснение: Timer.publish — нативный способ избежать ручного управления таймерами.

Заключение

Эти 12 промтов покрывают 80% ежедневных задач iOS-разработчика. Сохраните подборку, чтобы быстро генерировать рабочий код без лишних правок. Если хотите глубже разобраться в каждой технологии — заглядывайте в другие статьи блога Asibiont. А какой промт используете чаще всего? Делитесь в комментариях!

← Все статьи

Комментарии

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