If you're an iOS developer, you've probably spent hours searching Stack Overflow for the right way to animate a SwiftUI view or debug a Core Data fault. Large language models can accelerate that process — but only if you ask the right questions. A poorly phrased prompt leads to generic, sometimes incorrect code. A well-structured prompt acts like a senior engineer reviewing your work. This article gives you a set of battle-tested prompts for SwiftUI, UIKit, Core Data, and Combine, with concrete examples and explanations. I've used these with real projects and they map directly to Apple's official documentation (developer.apple.com) and Swift.org guides.
Why Prompting Matters for iOS
Apple's frameworks are huge. SwiftUI alone has over 2,000 modifiers, and UIKit still powers most production apps. A generic prompt like "make a login screen" gives you a forgettable result. But a prompt that specifies state management, dependency injection, and accessibility will return code that follows Apple's Human Interface Guidelines and Swift API Design Guidelines. The following examples are designed to be copy-paste modified for your own codebase.
12 Practical Prompts
1. SwiftUI View with MVVM and Combine
Prompt:
Create a SwiftUI view for a user profile screen. Use the MVVM pattern, combine @Published properties with Combine, inject a network service, and handle loading and error states. Include a preview with mock data.
Example result (key parts):
class ProfileViewModel: ObservableObject {
@Published var profile: Profile?
@Published var errorMessage: String?
private let service: ProfileServiceProtocol
init(service: ProfileServiceProtocol) {
self.service = service
}
func load() {
service.fetchProfile()
.sink { [weak self] completion in
if case .failure(let error) = completion {
self?.errorMessage = error.localizedDescription
}
} receiveValue: { [weak self] profile in
self?.profile = profile
}
.store(in: &cancellables)
}
}
Why it works: It forces the model to follow Apple's recommended MVVM pattern and includes error handling, a common oversight.
2. UIKit UITableView with Diffable Data Source
Prompt:
Implement a UITableView in UIKit that uses UITableViewDiffableDataSource for a contact list. Show how to perform snapshot updates when contact data changes. Use cells with custom styling.
Example with diffable datasource:
dataSource = UITableViewDiffableDataSource<Section, Contact>(tableView: tableView) { tableView, indexPath, contact in
let cell = tableView.dequeueReusableCell(withIdentifier: "ContactCell", for: indexPath)
cell.textLabel?.text = contact.name
return cell
}
var snapshot = NSDiffableDataSourceSnapshot<Section, Contact>()
snapshot.appendSections([.main])
snapshot.appendItems(contacts)
dataSource.apply(snapshot, animatingDifferences: true)
3. Core Data Model and Fetch Request
Prompt:
Design a Core Data model for a Task app with attributes: name, dueDate, priority, and completed. Write an NSFetchRequest that filters tasks due today within a certain priority, sorted by due date. Include the managed object subclass.
Fetch request example:
let request: NSFetchRequest<Task> = Task.fetchRequest()
request.predicate = NSPredicate(format: "dueDate >= %@ AND dueDate <= %@ AND priority == %@", startOfDay, endOfDay, Priority.high.rawValue)
request.sortDescriptors = [NSSortDescriptor(key: "dueDate", ascending: true)]
4. Combine Operator Chain for Search
Prompt:
Write a Combine pipeline that reacts to a search text field in SwiftUI, debounces input by 300ms, removes duplicates, filters non-empty strings, and calls an API. Handle errors and cancellation.
Pipeline example:
$searchText
.debounce(for: .seconds(0.3), scheduler: DispatchQueue.main)
.removeDuplicates()
.filter { !$0.isEmpty }
.flatMap { query in
api.search(with: query)
.catch { error in
Just([])
}
}
.assign(to: \.results, on: self)
5. Unit Test for a ViewModel
Prompt:
Write unit tests for a SwiftUI ViewModel that uses Combine and a network service. Use mock service to test success, failure, and loading states. Use XCTest expectations to wait for Combine publishers.
Test example:
func testLoadSuccess() {
let mockService = MockProfileService(result: .success(profile))
let vm = ProfileViewModel(service: mockService)
vm.load()
expectation(for: \.profile, equals: profile)
waitForExpectations(timeout: 1)
}
6. Performance: Reduce SwiftUI View Recomputations
Prompt:
Explain and demonstrate common reasons SwiftUI views get recomputed unnecessarily. Provide a visual example using a child view that doesn't depend on the changed state. Show use of @State, @ObservableObject, and Equatable.
Example: Use a child view that conforms to Equatable and pass a value type, which lets SwiftUI skip updates when the value hasn't changed.
7. Async/await Networking in Swift
Prompt:
Rewrite an existing URLSession dataTask-based networking code using Swift async/await. Show cancellation with URLSession.shared.data(from:) and handle errors with a custom error type.
Example:
func fetchData(from url: URL) async throws -> Data {
let (data, response) = try await URLSession.shared.data(from: url)
guard let http = response as? HTTPURLResponse, http.statusCode == 200 else {
throw NetworkError.badServerResponse
}
return data
}
8. Accessibility in SwiftUI
Prompt:
Enhance a SwiftUI custom control (like a stepper) with accessibility labels, values, and actions. Show how to use accessibilityAdjustableAction to support VoiceOver gestures. Use the Accessibility Inspector tips from Apple's docs.
Example: Add .accessibilityValue(Text("Number: \(value)")) and implement accessibilityAdjustableAction to increment/decrement.
9. Debug Memory Leaks with Instruments
Prompt:
List the most common retain cycles in UIKit and SwiftUI. Write a debug helper that prints memory warnings. Explain how to use Xcode's Memory Graph Debugger to find leaks, and provide code for weak vs unowned.
Table: retain cycle sources
| Pattern | Issue | Fix |
|---|---|---|
Closures{ [weak self] in ... } |
self captured strongly | use weak self |
| Timer with block | timer retains self | invalidate timer |
Combine store(in:) |
used incorrectly | use Set<AnyCancellable> with weak self |
10. Migrate from SQLite to Core Data (or vice versa)
Prompt:
Compare Core Data vs SQLite for data persistence in an iOS app. Provide a migration plan and code for lightweight and heavyweight migration. Discuss zombie entities and external changes.
Key point: Core Data is not a database — it's an object graph persistence framework. Use lightweight migration for simple changes, and mapping model for complex ones.
11. Swift Concurrency in an Existing Codebase
Prompt:
Outline a strategy to incrementally move a UIKit project from callbacks and Combine to Swift Concurrency. Show how to wrap an existing method that uses @escaping completion handler into an async function using withCheckedThrowingContinuation.
Bridge example:
func legacyFetch(completion: (Result<Data, Error>) -> Void)
func asyncFetch() async throws -> Data {
try await withCheckedThrowingContinuation { continuation in
legacyFetch { result in
continuation.resume(with: result)
}
}
}
12. Core Data Relationship and Model Design
Prompt:
Design a Core Data model for a blog with authors, posts, and comments. Show the proper inverse relationships and delete rules. Write a fetch request that gets all posts by a specific author with the comments count.
Relationship example: Set author.posts as inverse of post.author, delete rule cascade for comments.
Final Thoughts
These prompts work best when you treat them as a starting point. Modify them to include your exact model names, deployment targets, and edge cases. Apple's official documentation at developer.apple.com is the authoritative source for any API details; use LLM output as a companion, not a replacement. Start with a prompt that asks for a concrete, compilable example, then iterate by asking for test cases and performance considerations. That's how you turn a code generator into a productivity multiplier.
Comments