RORK LABJP
CLOUD — Rork Max compiles native Swift on a fleet of cloud Macs, so you never download Xcode or need to own a MacPLATFORM — Rork Max targets iPhone, iPad, Apple Watch, and Vision Pro, and reaches games, widgets, and Live ActivitiesSHIP — Build in the browser, preview through a streaming simulator, install on device via QR code, and submit to the App Store without leaving RorkSPLIT — Regular Rork generates cross-platform apps with React Native and Expo. Reach for it to ship broadly and fast, and for Max when you need Apple-specific depthCREDIT — The free tier works out to roughly five prompts a week. It helps to budget the cost of trying something separately from the cost of finishing itPRICE — Rork Max sits on the $200/month Max plan, while regular Rork starts free with paid plans from $25/monthCLOUD — Rork Max compiles native Swift on a fleet of cloud Macs, so you never download Xcode or need to own a MacPLATFORM — Rork Max targets iPhone, iPad, Apple Watch, and Vision Pro, and reaches games, widgets, and Live ActivitiesSHIP — Build in the browser, preview through a streaming simulator, install on device via QR code, and submit to the App Store without leaving RorkSPLIT — Regular Rork generates cross-platform apps with React Native and Expo. Reach for it to ship broadly and fast, and for Max when you need Apple-specific depthCREDIT — The free tier works out to roughly five prompts a week. It helps to budget the cost of trying something separately from the cost of finishing itPRICE — Rork Max sits on the $200/month Max plan, while regular Rork starts free with paid plans from $25/month
Articles/Dev Tools
Dev Tools/2026-06-16Advanced

Adding SwiftData to a SwiftUI App Generated by Rork Max

Rork Max can produce polished SwiftUI screens, but persistence often stops at @State. Here is how I layer SwiftData onto generated code: model design, wiring the container to views, and a schema migration pattern that survives shipping.

Rork Max231SwiftData2SwiftUI64PersistenceMigration

Premium Article

One evening I was looking at the SwiftUI code Rork Max gave me after I asked it to "build a habit tracker," and my hand froze on the trackpad. The screens were more thoughtful than I expected — the list, the checkboxes, all neatly laid out. But every time I relaunched the app, every habit I had entered was gone.

The reason was obvious the moment I opened the source. The data lived only in @State private var habits: [Habit] = [], never written to disk at all. Rork Max is excellent at producing a screen that looks like it works as fast as possible, but it does not design the persistence layer for you. That was the lesson of the night.

In this article I want to record the full path of taking that generated code and growing it into an app that survives a relaunch, with the actual code I wrote. I am assuming iOS 17 or later and that you can open the SwiftUI Rork Max emits in Xcode or a cloud build.

Why staying on @State eventually breaks

Freshly generated code usually looks like this.

struct Habit: Identifiable {
    let id = UUID()
    var name: String
    var doneToday: Bool
}
 
struct ContentView: View {
    @State private var habits: [Habit] = [
        Habit(name: "Morning walk", doneToday: false),
        Habit(name: "Reading", doneToday: false)
    ]
 
    var body: some View {
        List($habits) { $habit in
            Toggle(habit.name, isOn: $habit.doneToday)
        }
    }
}

As a screen, this is finished. But @State is in-memory state tied to the lifetime of the view, so it disappears when the process ends. Good enough for a demo, not viable for an app people open every day.

Many of us reach for serializing a Codable into UserDefaults as JSON next. I did exactly that in my early apps. The trouble is that once items grow and you need relationships or query conditions, reading and writing the whole JSON blob gets painful fast. SwiftData is designed for data that grows, so as an indie developer I have found that spending a little effort up front to move onto it pays off later.

Step 1: Replace the struct with @Model

The first move is turning the struct into an @Model class. The catch is that it becomes a final class rather than a struct — miss that and it will not compile.

import SwiftData
 
@Model
final class Habit {
    var name: String
    var doneToday: Bool
    var createdAt: Date
 
    init(name: String, doneToday: Bool = false, createdAt: Date = .now) {
        self.name = name
        self.doneToday = doneToday
        self.createdAt = createdAt
    }
}

Once @Model is applied, SwiftData tracks property changes automatically and treats the object as something to persist. You do not need to hold an id by hand; SwiftData manages an internal persistent identifier.

There is a judgment call here. If the generated code still has let id = UUID(), you can drop it as long as your views and animations do not depend on it. But if a ForEach references it via id:, I prefer to keep an explicit UUID property as a stable identifier. Rork Max output tends to be ambiguous here, so it is safest to check how ForEach is used before deciding.

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
A step-by-step path from @State-only generated code to SwiftData @Model storage
VersionedSchema and MigrationPlan code that lets your schema grow without breaking the app
A ModelContainer fallback design that keeps the app launching even when migration fails
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

Related Articles

Dev Tools2026-07-18
The Generated Screen That Quietly Jams at AX5 and in German — Putting Layout Resilience Checks on Rork Max SwiftUI
A record of running every Rork Max generated SwiftUI screen through pseudolocalization and the largest text size to find exactly where it jams. Covers when to reach for ViewThatFits, ScaledMetric and layoutPriority, plus the snapshot checks that catch regressions every time you regenerate.
Dev Tools2026-07-12
A symbolEffect Field Memo: Making Icons Move Nicely in Your Rork Max App
Animate SF Symbols in a Swift app generated by Rork Max using bounce, pulse, variableColor, and contentTransition, with working code, OS-version gating, and the mistakes I made from over-animating.
Dev Tools2026-07-09
Getting Rork Max's Swift Through Swift 6's Strict Concurrency Checking
A field record of taking a Rork Max-generated SwiftUI app through Swift 6 complete concurrency checking: 217 warnings cleared target by target, where @MainActor actually belongs, and measured before/after numbers.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →