15 Prompts for Swift and iOS Development: SwiftUI, UIKit, Core Data

Introduction

As an iOS developer, you likely spend hours debugging, writing boilerplate, or searching for the right API. AI assistants can cut that time significantly—if you know the right prompts. This collection of 15 battle-tested prompts covers SwiftUI, UIKit, Core Data, and Combine. Each prompt is paired with a real usage example and code snippet, so you can drop them into your workflow immediately.

Why these prompts work: They are specific, include context (e.g., ‘iOS 17, Swift 5.9’), and request concrete outputs (code, explanations, alternatives). General questions like ‘how do I use Core Data?’ yield generic answers. These prompts force the AI to deliver production-ready solutions.


SwiftUI Prompts

1. Custom View Modifier

Prompt: ‘Generate a SwiftUI custom ViewModifier for a card-style view with shadow, rounded corners, and a configurable background color. Include a usage example with @State for toggle effects.’

Why it works: It specifies properties (shadow, corner radius, color) and a concrete use case (toggle effect).

Example output (abbreviated):

struct CardModifier: ViewModifier {
    let backgroundColor: Color
    func body(content: Content) -> some View {
        content
            .padding(20)
            .background(backgroundColor)
            .cornerRadius(16)
            .shadow(color: .black.opacity(0.2), radius: 8, x: 0, y: 4)
    }
}

extension View {
    func cardStyle(backgroundColor: Color = .white) -> some View {
        modifier(CardModifier(backgroundColor: backgroundColor))
    }
}

// Usage:
struct ContentView: View {
    @State private var isToggled = false
    var body: some View {
        VStack {
            Text("Hello, SwiftUI!")
                .cardStyle(backgroundColor: isToggled ? .yellow : .white)
            Button("Toggle") { isToggled.toggle() }
        }
    }
}

2. LazyVGrid with Dynamic Data

Prompt: ‘Write a SwiftUI view that uses LazyVGrid with two flexible columns, loads an array of strings from a ViewModel, and displays them as tappable buttons with haptic feedback. Use iOS 17 and Swift 5.9.’

Why it works: It specifies grid type, data source, interaction, and iOS version.

Example output (abbreviated):

class ItemViewModel: ObservableObject {
    @Published var items = ["Alpha", "Beta", "Gamma", "Delta"]
}

struct GridView: View {
    @StateObject var vm = ItemViewModel()
    let columns = [GridItem(.flexible()), GridItem(.flexible())]

    var body: some View {
        ScrollView {
            LazyVGrid(columns: columns, spacing: 12) {
                ForEach(vm.items, id: \.self) { item in
                    Button(action: {
                        let impact = UIImpactFeedbackGenerator(style: .medium)
                        impact.impactOccurred()
                    }) {
                        Text(item)
                            .frame(maxWidth: .infinity)
                            .padding()
                            .background(Color.blue.opacity(0.2))
                            .cornerRadius(8)
                    }
                }
            }
            .padding()
        }
    }
}

3. NavigationStack with Programmatic Push

Prompt: ‘Show how to use NavigationStack in iOS 17 to push a detail view programmatically via a boolean state, not a NavigationLink. Include a simple list and a button that triggers navigation.’

Why it works: It asks for a specific API (NavigationStack) and a specific behavior (programmatic push).

Example output (abbreviated):

struct ContentView: View {
    @State private var isShowingDetail = false
    let items = ["Item 1", "Item 2"]

    var body: some View {
        NavigationStack {
            List(items, id: \.self) { item in
                Text(item)
            }
            .navigationDestination(isPresented: $isShowingDetail) {
                DetailView()
            }
            .toolbar {
                Button("Go to Detail") { isShowingDetail = true }
            }
        }
    }
}

UIKit Prompts

4. Custom UICollectionView Layout

Prompt: ‘Implement a custom UICollectionViewCompositionalLayout that shows a grid of squares (1:1 ratio) with 3 columns and 4 points spacing. Use a diffable data source with a simple model struct. Target iOS 16+.’

Why it works: It specifies layout type, item aspect ratio, spacing, data source, and minimum deployment target.

Example output (abbreviated):

struct PhotoItem: Hashable {
    let id = UUID()
    let title: String
}

class ViewController: UIViewController {
    enum Section { case main }
    var collectionView: UICollectionView!
    var dataSource: UICollectionViewDiffableDataSource<Section, PhotoItem>!

    override func viewDidLoad() {
        super.viewDidLoad()
        configureLayout()
        configureDataSource()
    }

    func configureLayout() {
        let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1/3), heightDimension: .fractionalWidth(1/3))
        let item = NSCollectionLayoutItem(layoutSize: itemSize)
        item.contentInsets = NSDirectionalEdgeInsets(top: 2, leading: 2, bottom: 2, trailing: 2)
        let group = NSCollectionLayoutGroup.horizontal(layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalWidth(1/3)), subitems: [item])
        let section = NSCollectionLayoutSection(group: group)
        collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: UICollectionViewCompositionalLayout(section: section))
        view.addSubview(collectionView)
    }
}

5. Programmatic Auto Layout Constraints

Prompt: ‘Write a UIViewController that adds a UILabel and a UIButton programmatically using Auto Layout anchors. The label should be centered horizontally and 20 points from the top safe area. The button should be below the label with 20 points spacing and center aligned.’

Why it works: It specifies elements, positions, and spacing explicitly.

Example output (abbreviated):

class MyViewController: UIViewController {
    let label = UILabel()
    let button = UIButton(type: .system)

    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(label)
        view.addSubview(button)
        label.translatesAutoresizingMaskIntoConstraints = false
        button.translatesAutoresizingMaskIntoConstraints = false

        NSLayoutConstraint.activate([
            label.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            label.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20),
            button.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            button.topAnchor.constraint(equalTo: label.bottomAnchor, constant: 20)
        ])
    }
}

6. TableView with Swipe Actions

Prompt: ‘Create a UITableViewController with swipe-to-delete and a custom ‘Favorite’ action using trailingSwipeActionsConfigurationForRowAt. Use a simple array of strings as data. iOS 15+.’

Why it works: It asks for a specific delegate method and makes the action custom.

Example output (abbreviated):

class MyTableViewController: UITableViewController {
    var items = ["Apple", "Banana", "Cherry"]

    override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
        let delete = UIContextualAction(style: .destructive, title: "Delete") { _, _, completion in
            self.items.remove(at: indexPath.row)
            tableView.deleteRows(at: [indexPath], with: .fade)
            completion(true)
        }
        let favorite = UIContextualAction(style: .normal, title: "Favorite") { _, _, completion in
            print("Favorited \(self.items[indexPath.row])")
            completion(true)
        }
        favorite.backgroundColor = .systemYellow
        return UISwipeActionsConfiguration(actions: [delete, favorite])
    }
}

Core Data Prompts

7. Setting Up Core Data Stack

Prompt: ‘Generate a Core Data stack using NSPersistentContainer for iOS 17, including a managed object model with a ‘Task’ entity (attributes: title, dueDate, isCompleted). Show how to save and fetch in a view controller.’

Why it works: It specifies container type, entity, attributes, and basic operations.

Example output (abbreviated):

class CoreDataManager {
    static let shared = CoreDataManager()
    let container: NSPersistentContainer

    init() {
        container = NSPersistentContainer(name: "MyModel")
        container.loadPersistentStores { _, error in
            if let error = error { fatalError("Failed to load store: \(error)") }
        }
    }

    func saveContext() {
        let context = container.viewContext
        if context.hasChanges { try? context.save() }
    }

    func fetchTasks() -> [Task] {
        let request: NSFetchRequest<Task> = Task.fetchRequest()
        return (try? container.viewContext.fetch(request)) ?? []
    }
}

8. Batch Delete with Predicate

Prompt: ‘Show how to use NSBatchDeleteRequest to delete all tasks where isCompleted is true. Include a fetch request for count before and after, and handle the context refresh. Swift 5.9, Core Data.’

Why it works: It asks for a specific API and requires post-delete refresh.

Example output (abbreviated):

func deleteCompletedTasks() {
    let context = CoreDataManager.shared.container.viewContext
    let fetchRequest: NSFetchRequest<NSFetchRequestResult> = Task.fetchRequest()
    fetchRequest.predicate = NSPredicate(format: "isCompleted == YES")
    let batchDelete = NSBatchDeleteRequest(fetchRequest: fetchRequest)
    batchDelete.resultType = .resultTypeObjectIDs

    guard let result = try? context.execute(batchDelete) as? NSBatchDeleteResult,
          let ids = result.result as? [NSManagedObjectID] else { return }

    NSManagedObjectContext.mergeChanges(fromRemoteContextSave: [NSDeletedObjectsKey: ids], into: [context])
}

9. Relationship and Fetching

Prompt: ‘Create a Core Data model with two entities: ‘Author’ (name) and ‘Book’ (title, year). Author has a one-to-many relationship to Book. Write a fetch to get all books by a given author sorted by year descending.’

Why it works: It models a common relationship and a specific sort order.

Example output (abbreviated):

func books(by author: Author) -> [Book] {
    let request: NSFetchRequest<Book> = Book.fetchRequest()
    request.predicate = NSPredicate(format: "author == %@", author)
    request.sortDescriptors = [NSSortDescriptor(key: "year", ascending: false)]
    return (try? CoreDataManager.shared.container.viewContext.fetch(request)) ?? []
}

Combine Prompts

10. Debounced Search with Combine

Prompt: ‘Implement a search bar in SwiftUI that uses Combine’s debounce operator to wait 300ms after the user stops typing before calling an API. Use @Published property and sink.’

Why it works: It combines SwiftUI, Combine, and a real-world pattern.

Example output (abbreviated):

class SearchViewModel: ObservableObject {
    @Published var query = ""
    @Published var results: [String] = []
    private var cancellable: AnyCancellable?

    init() {
        cancellable = $query
            .debounce(for: .seconds(0.3), scheduler: RunLoop.main)
            .removeDuplicates()
            .sink { [weak self] q in
                self?.search(q)
            }
    }

    func search(_ query: String) {
        // Simulated API call
        results = ["Result for \(query)"]
    }
}

11. Combine with URLSession

Prompt: ‘Write a Combine publisher that performs a GET request to a JSON API, decodes the response into a [User] array (User: Codable with id and name), and handles errors. Use dataTaskPublisher and decode operator.’

Why it works: It chains multiple operators and includes error handling.

Example output (abbreviated):

struct User: Codable {
    let id: Int
    let name: String
}

func fetchUsers() -> AnyPublisher<[User], Error> {
    guard let url = URL(string: "https://api.example.com/users") else {
        return Fail(error: URLError(.badURL)).eraseToAnyPublisher()
    }
    return URLSession.shared.dataTaskPublisher(for: url)
        .map(\.data)
        .decode(type: [User].self, decoder: JSONDecoder())
        .eraseToAnyPublisher()
}

Advanced & Debugging Prompts

12. SwiftUI Previews with Mock Data

Prompt: ‘Create a SwiftUI preview for a view that accepts a binding to a list of items. Use a mock data array with @State in the preview provider.’

Why it works: It targets a common pain point (previews with bindings).

Example output (abbreviated):

struct ItemListView: View {
    @Binding var items: [String]
    var body: some View {
        List(items, id: \.self) { Text($0) }
    }
}

struct ItemListView_Previews: PreviewProvider {
    static var previews: some View {
        ItemListView(items: .constant(["A", "B", "C"]))
    }
}

13. Debugging with OSLog

Prompt: ‘Show how to use OSLog for debugging a Core Data fetch. Include dynamic log messages with string interpolation and a custom log category.’

Why it works: It teaches a best practice (structured logging) over print().

Example output (abbreviated):

import os
let log = OSLog(subsystem: "com.example.app", category: "CoreData")

func fetchItems() {
    os_log("Fetching items with predicate: %@", log: log, type: .debug, "isCompleted == true")
    // fetch code
}

14. Async/Await with UIKit

Prompt: ‘Convert a UIKit button action to use async/await instead of completion handlers. Assume an existing async function fetchData() throws -> String. Show the button handler with Task and error handling.’

Why it works: It bridges modern Swift concurrency with UIKit.

Example output (abbreviated):

@objc func buttonTapped() {
    Task {
        do {
            let result = try await fetchData()
            print("Data: \(result)")
        } catch {
            print("Error: \(error)")
        }
    }
}

15. SwiftUI Animations with GeometryEffect

Prompt: ‘Create a custom GeometryEffect that animates a view from a source frame to a destination frame (like a hero transition). Include a trigger with @State and withAnimation.’

Why it works: It tackles a complex animation pattern.

Example output (abbreviated):

struct HeroEffect: GeometryEffect {
    var progress: CGFloat
    var animatableData: CGFloat {
        get { progress }
        set { progress = newValue }
    }

    func effectValue(size: CGSize) -> ProjectionTransform {
        let translation = CGAffineTransform(translationX: 0, y: size.height * (1 - progress))
        return ProjectionTransform(translation)
    }
}

struct ContentView: View {
    @State private var isExpanded = false
    var body: some View {
        RoundedRectangle(cornerRadius: 12)
            .frame(width: 100, height: 100)
            .modifier(HeroEffect(progress: isExpanded ? 1 : 0))
            .onTapGesture {
                withAnimation(.spring()) { isExpanded.toggle() }
            }
    }
}

Conclusion

These 15 prompts cover the most common tasks in iOS development—from SwiftUI layouts to Core Data batch deletes and Combine pipelines. The key is specificity: include framework version, data types, and expected behavior. Next time you hit a roadblock, copy a prompt, adjust the parameters, and let AI generate the boilerplate. Your future self (and your code reviewer) will thank you.

Call to action: Bookmark this list and try one prompt today. Modify it to your project’s naming conventions and share your own battle-tested prompts in the comments below.

← All posts

Comments