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. А какой промт используете чаще всего? Делитесь в комментариях!
Комментарии