RORK LABJP
MAX — Rork Max generates native Swift for iPhone, iPad, Apple Watch, Apple TV, and Vision Pro, with 2-click App Store publishing and no Xcode requiredSTACK — Standard Rork builds cross-platform mobile apps with React Native (Expo); choosing between the two by use case is the key decisionFOCUS — Unlike web-first tools such as Bolt or Lovable, Rork specializes in native iOS and Android app generationBUGS — A hands-on review reports Rork resolved about 70% of bugs without manual help, with the remaining 30% needing edits in the exported codebaseFUNDING — Rork raised $2.8M from a16z (Andreessen Horowitz)PRICING — It is free to start, with paid plans from $25/month, so you can try before committingMAX — Rork Max generates native Swift for iPhone, iPad, Apple Watch, Apple TV, and Vision Pro, with 2-click App Store publishing and no Xcode requiredSTACK — Standard Rork builds cross-platform mobile apps with React Native (Expo); choosing between the two by use case is the key decisionFOCUS — Unlike web-first tools such as Bolt or Lovable, Rork specializes in native iOS and Android app generationBUGS — A hands-on review reports Rork resolved about 70% of bugs without manual help, with the remaining 30% needing edits in the exported codebaseFUNDING — Rork raised $2.8M from a16z (Andreessen Horowitz)PRICING — It is free to start, with paid plans from $25/month, so you can try before committing
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 Max166SwiftDataSwiftUI49PersistenceMigration

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-06-15
Showing Live Progress in the Dynamic Island from a Rork Max Swift App
How to add an ActivityKit Live Activity to a Swift app generated by Rork Max so progress shows in the Dynamic Island, plus the update-related pitfalls I hit in production.
Dev Tools2026-05-17
Testing Rork Max SwiftUI Features on a Real Wallpaper App — What Worked, What Needed Fixes
As a developer with 50 million cumulative app downloads, I put Rork Max's SwiftUI generation through its paces using my actual wallpaper app as the benchmark. Here's an honest breakdown of features that worked, features that needed adjustment, and features I ended up writing by hand.
Dev Tools2026-05-16
Rork Max SwiftUI App Crash Logs Are Unreadable: The dSYM Upload Pitfall
Fix Unsymbolicated crash reports in Firebase Crashlytics for Rork Max SwiftUI apps. Learn the correct dSYM upload configuration with real examples from indie app development.
📚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 →