Generating views with AI (and reading the code)
Build the EntryList and EntryEditor screens by prompting well, then verify the output against your spec.
Now you'll generate real screens. The skill is prompting with enough context that the output fits your app — same data model, same spec, same conventions — and then reading it well enough to trust it.
Generate the list screen
iOS 17+, SwiftUI + SwiftData. I have this model: [paste Entry.swift]. Build `EntryListView`: a NavigationStack with a List of entries sorted by createdAt descending, using @Query. Each row shows the aiTitle if present else the first line of body, plus the date in .secondary. A toolbar "+" button presents an EntryEditor in a .sheet. Support swipe-to-delete. Public APIs only; return the full file.
SCTB again: stack (iOS 17+, SwiftUI + SwiftData), target (EntryListView), behavior (rows, sheet, swipe-to-delete), constraint (public APIs only).
A good result looks like this. Read the annotations — they map directly onto the five fundamentals from the last lesson:
import SwiftUI
import SwiftData
struct EntryListView: View {
@Environment(\.modelContext) private var context
@Query(sort: \Entry.createdAt, order: .reverse) private var entries: [Entry]
@State private var showingEditor = false
var body: some View {
NavigationStack {
List {
ForEach(entries) { entry in
NavigationLink(value: entry) {
EntryRow(entry: entry)
}
}
.onDelete(perform: delete)
}
.navigationTitle("DayOne")
.navigationDestination(for: Entry.self) { EntryDetailView(entry: $0) }
.toolbar {
Button { showingEditor = true } label: { Image(systemName: "plus") }
}
.sheet(isPresented: $showingEditor) {
EntryEditorView()
}
}
}
private func delete(_ offsets: IndexSet) {
for i in offsets { context.delete(entries[i]) }
}
}
private struct EntryRow: View {
let entry: Entry
var body: some View {
VStack(alignment: .leading, spacing: 4) {
Text(entry.aiTitle ?? entry.body.firstLine)
.font(.headline)
.lineLimit(1)
Text(entry.createdAt, format: .dateTime.month().day().year())
.font(.caption)
.foregroundStyle(.secondary)
}
}
}entry.body.firstLine isn't a real Swift API — the model invented a convenient-sounding helper. This is exactly the 10% you must catch. The fix is a tiny extension, which you'd ask for next. The file also references EntryEditorView and EntryDetailView, which don't exist yet — you'll build those in the next lesson and the lab, so those two "Cannot find in scope" errors are expected until then.
extension String {
/// First line of the string, or a placeholder if empty.
var firstLine: String {
split(separator: "\n").first.map(String.init) ?? "Untitled"
}
}When code won't compile, read the error's first line and the file/line it points to before re-prompting. Half the time the fix is a one-line helper like the above, and you'll paste the exact error to the model: "firstLine doesn't exist — add an extension on String."