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-17Advanced

Why Your Rork Max Native Swift Widget Freezes After Day One — Designing the TimelineProvider Refresh Budget

Native Swift home screen widgets generated by Rork Max stop rotating after the first day unless you understand the TimelineProvider refresh budget. Here is how reloadPolicy, App Groups, and deep links fit together in a real app.

Rork Max166WidgetKit7Swift25Home Screen WidgetIndie Development13

Premium Article

If you run wallpaper apps or affirmation apps as an indie developer for any length of time, the request "show one fresh image on the home screen each day" comes up sooner or later. Once Rork Max started emitting native Swift widgets, I retrofitted WidgetKit onto one of my existing apps — and the very first build tripped me up. It rotated daily in the simulator, but when I installed it on a real device and checked the next morning, the widget was frozen on yesterday's single image.

The cause was that the generated TimelineProvider never decided when or how much refresh to schedule. A WidgetKit timeline is not a cron. Ship Rork Max's output without designing this part, and you get the nastiest failure mode of all: it works on day one and dies on day two.

Widgets freeze because they exhaust the budget

To protect battery life, WidgetKit caps how many refreshes each widget can receive per day — a refresh budget. Apple's public guidance puts this at roughly 40 to 70 refreshes per day for a frequently viewed home screen widget, and both consuming the entries your TimelineProvider returns and your calls to reloadTimelines(ofKind:) draw down that same budget.

The key detail: regeneration of the next timeline does not happen automatically once the last entry passes. If getTimeline returns "just one entry for midnight today" and you specify no reloadPolicy, the system has no idea when to load the next one. The display stays pinned to that final entry. The reason you miss it in the simulator is that the timeline is regenerated every time you run a debug build — that is a different world from production behavior.

Because the budget does not recover until the next day once spent, the design has two goals. First, keep the daily refresh count inside the budget. Second, reliably hand off to the next day within that limit. For a daily rotation, the truly necessary refresh is once per day. Rather than slashing refreshes out of budget anxiety, it is safer to use reloadPolicy correctly to state exactly when the next refresh should happen.

Always declare "when to wake up next" with reloadPolicy

The policy argument of Timeline(entries:policy:) has three forms. .atEnd reloads after the last entry passes, .after(date) reloads at a specified time, and .never means no reload. For a daily widget, naming midnight tomorrow with .after is the most predictable.

import WidgetKit
import SwiftUI
 
struct DailyEntry: TimelineEntry {
    let date: Date
    let title: String
    let imageName: String
}
 
struct DailyProvider: TimelineProvider {
    func placeholder(in context: Context) -> DailyEntry {
        DailyEntry(date: Date(), title: "Today's Pick", imageName: "placeholder")
    }
 
    func getSnapshot(in context: Context, completion: @escaping (DailyEntry) -> Void) {
        completion(currentEntry())
    }
 
    func getTimeline(in context: Context, completion: @escaping (Timeline<DailyEntry>) -> Void) {
        let entry = currentEntry()
 
        // Name midnight tomorrow (device local) as the next refresh point
        let calendar = Calendar.current
        let startOfTomorrow = calendar.startOfDay(
            for: calendar.date(byAdding: .day, value: 1, to: entry.date)!
        )
 
        let timeline = Timeline(entries: [entry], policy: .after(startOfTomorrow))
        completion(timeline)
    }
}

The crux here is narrowing the entries to "one for today" and setting reloadPolicy to .after(midnight tomorrow). The system then calls getTimeline again around midnight, where "tomorrow's image" gets resolved. The effective refresh is once a day, which does not strain the budget.

.atEnd works too, but with only one entry queued, "the last entry" equals "what is showing now," and the reload timing becomes ambiguous. If you want a clean switch at the date boundary, holding the time with .after behaves as intended. My own first build used .atEnd, froze the next day, and was fixed by switching to .after — so for daily use I now default to .after.

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 daily-rotating widget design that keeps refreshing past day one by working with reloadPolicy and the system refresh budget
An App Group pattern that lets the main app and the widget share the same content so today's entry resolves without networking
Deep-link design that routes a widget tap to the correct screen via a Widget URL, with the common failures isolated
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-04-05
Rork Max × WidgetKit & Live Activities Complete Guide 2026 — Dynamic Island Implementation
A complete guide to implementing iOS Widgets, Lock Screen widgets, and Dynamic Island Live Activities with Rork Max. Covers WidgetKit fundamentals, Timeline update strategies, App Intents integration, and monetization.
Dev Tools2026-06-16
Putting Your Rork Max Native App's Content into iPhone Search — Becoming a 'Findable' App with Core Spotlight
Index the content of the native Swift app Rork Max generates into Core Spotlight, so users reach a specific in-app screen straight from iPhone search. Covers adding, updating, and removing index entries, plus the production trap of stale search results, from an indie developer's view.
Dev Tools2026-06-16
Designing CloudKit Sync in a Rork Max Native App — Handling Conflicts and Deletes
You want the same data on iPhone and iPad. When you add CloudKit to a Swift app generated by Rork Max, the hard part is not saving — it is conflicts and deletes. Here are the design decisions I settled on.
📚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 →