A Sabbatical from the Web

After years of building on AWS with Lambda, DynamoDB, Cognito, and the rest of the typical stack, the author of Max reHIT Workout decided to take a different approach. His previous projects—from a book-ranking tracker to a complex accounting tool—were all cloud-native, web-based builds. While AWS was straightforward in parts, services like Cognito consumed more time than they saved, and the documentation often fell short. AppSync was dismissed as too opinionated, forcing toolchains and processes he didn't want.

The web itself, with its constant front-end framework churn, had become exhausting. The decision was made to build the next app natively on iOS using SwiftUI.

The SwiftUI Learning Curve

SwiftUI proved to be an enormous paradigm shift. Having never fully embraced reactive programming on the web, the author found the magic of a UI that updates based on data changes to be compelling. But beyond simple demos, that magic requires a deep understanding of property wrappers and the "dark arts" of binding and observable state. Compiler quirks and elusive bugs were common, but for someone with modest UI skills, SwiftUI was a way to be productive without touching Xcode's Interface Builder—it's just code.

The real complexity lay in assembling a complete application. Handling logged-in versus logged-out states, offline modes, ads, in-app purchases, syncing, and onboarding all had to be re-learned in a new paradigm. A deliberate choice made this harder: the app works perfectly without a login or immediate payment, as a reaction against fitness apps that demand both upfront. Supporting those "no-account" modes added significant complexity.

Data, Sync, and the Cloud

The initial plan was to keep the app simple, storing data with CoreData, UserDefaults, and for a large dataset, a JSON file. That worked, but only for a single device. When the decision came to support multiple devices, the approach changed.

The JSON file was moved to the cloud via CloudKit, but it didn't sync. The correct solution required migrating all data to CoreData and using the PersistentCloudKitContainer. With SwiftUI's @FetchRequest, this integration "just works" within a view. It syncs, scales, caches locally for offline use, and is free. The catch is that this convenience only applies within views. Accessing data outside of a view requires working around SwiftUI's view-centric tooling, which proved to be one of the main stumbling blocks.

A Cost-Benefit Analysis of Going Native

Was this faster or easier than web + AWS? Not at first. The learning curve was substantial. Now, with a complete project under his belt, the author has reusable Swift and SwiftUI components, making the next build faster. He advises staying away from protocols in SwiftUI, which caused the most compiler issues.

The obvious downside is platform lock-in to iOS. There is no website or Android version, and no recourse if Apple rejects the app. For this specific paid app, targeting iOS users who might find interval workout guidance valuable made that tradeoff acceptable.

Regarding the App Store commission: the fee is 15% under the Small Business Program, which the author considers worth it. Native in-app purchases and sign-in are better experiences than PayPal and Cognito. When you factor in the free, reliable cloud storage and syncing via CloudKit, Apple's cut seems reasonable—for a single-platform app. For a multi-platform product that doesn't leverage iOS services, the cost would rankle more.

For a next project, would the author repeat this choice? Yes, for certain kinds of properties, now that the tooling and patterns are familiar. But the answer shifts if you need to reach a broader audience without the resources to build native teams for each platform. An intriguing alternative mentioned is using SwiftUI as a foundation for generating front-end code for websites or even Android apps.