4 Apps, 4 Rejections — What I Learned from App Store Review

I launched 4 iOS apps in quick succession and got rejected on every single one. Here’s what happened and how to avoid the same traps. 1. IAP Products Registered But Not in the Binary App: Renio (subscription tracker) Guideline: 2.1(b) - App Completeness I created subscription products (Monthly, Yearly) in App Store Connect but submitted the app without implementing StoreKit. The products existed in the console but not in the code. ...

April 21, 2026 · 4 min · Young

Debugging SwiftUI Image Flickering: Three Bugs Stacked on Top of Each Other

The Problem I was building a music streaming app, and the album artwork kept flickering. Not just during track changes — even while playing the same song, the artwork would briefly disappear and reappear. The blurred background on the full player was especially bad. I figured it was slow image loading, so I added caching. Still flickered. Dug deeper and found three bugs stacked on top of each other. ...

April 21, 2026 · 3 min · Young

Handling Audio Interruptions in an iOS Music App with AVPlayer

The Problem I was building a Subsonic-based music streaming app. Background playback worked fine — until I noticed something odd: Play a song, send the app to the background Open YouTube and play a video (music stops — expected) Close the YouTube video Come back to the app: the pause button is showing, but no audio is playing The UI says “playing” while the actual audio is paused. Tapping the button toggles it to play, then you have to tap again. Broken UX. ...

April 21, 2026 · 2 min · Young

Why Storing Closures in SwiftUI @Observable Causes EXC_BAD_ACCESS

What I Was Trying to Do I was building an iOS music streaming app with detail views behind NavigationDestination. Each detail view had its own ViewModel, with API calls injected as closures. Something like this: @Observable final class PlaylistDetailVM { var songs: [Song] = [] var isLoading = false // API methods injected as closures private let fetchSongs: (String) async throws -> [Song] private let addToPlaylist: (String, [String]) async throws -> Void init( fetchSongs: @escaping (String) async throws -> [Song], addToPlaylist: @escaping (String, [String]) async throws -> Void ) { self.fetchSongs = fetchSongs self.addToPlaylist = addToPlaylist } } Created as @State inside NavigationDestination: ...

April 21, 2026 · 3 min · Young

Why Your SwiftData + CloudKit Widget Shows No Data (And How to Fix It)

The Widget Was Empty JournalMind syncs journal data with SwiftData + CloudKit. When I added a home screen widget to show today’s mood and weekly graph, the widget was always blank — even though the app itself showed data just fine. The Cause: Separate Processes A WidgetKit extension runs in a separate process from the main app. Even if you create the same ModelContainer, CloudKit sync only happens in the main app’s process. ...

April 21, 2026 · 4 min · Young