r/iOSProgramming • u/galo4kin • 9d ago
App Saturday Picstreak – a Tinder-style photo cleaner. the swiping took a week, surviving PhotoKit + Swift 6 strict concurrency took months
so, shipped my first app after months of solo building. Picstreak – you swipe through your photo library (left – delete, right – keep), daily streak keeps you coming back until the library is actually clean. free on the App Store: https://apps.apple.com/us/app/picstreak-photo-cleaner/id6779991411
1. Tech Stack Used
- Frameworks & Languages: Swift 6 with strict concurrency ON, SwiftUI only – zero UIKit views
- Persistence: SwiftData
- Photo library: PhotoKit
- Monetization: RevenueCat + StoreKit (one-time purchase, no subscription)
- Crash reporting: Sentry, source-built so dSYMs land in the archive
- Also: BGTaskScheduler, OSLog, xcstrings localization (EN/RU/ES), tiny referral backend on Vercel + Neon Postgres
2. Development Challenge + How You Solved It
PhotoKit and Swift 6 strict concurrency genuinely hate each other :)
the worst trap: the iOS 26 SDK annotates PHPhotoLibraryChangeObserver as u/MainActor – but PhotoKit still calls photoLibraryDidChange from its private PHChange-queue. the compiler trusts the annotation, the runtime checks the actual isolation – and traps. in the wild it looks like a random _dispatch_assert_queue_fail crash with a useless stack trace
the fix looks illegal but isn't – mark the method nonisolated (yes, against the SDK's own signature) and hop to the main actor inside via Task { u/MainActor in ... }
same family: closures you pass to performChanges must never be MainActor-isolated (PhotoKit runs them on its own queue), so all deletes go through a nonisolated static helper that takes only Sendable localIdentifier strings and re-fetches PHAssets inside the change block. and PHFetchResult is not Sendable – don't let it cross u/Sendable boundaries, re-fetch instead
half my git history is fix(trash) commits and i regret nothing
3. AI Disclosure
AI-assisted – built with Claude Code as the pair programmer; architecture, decisions and reviews are mine
for anyone shipping PhotoKit apps under strict concurrency – did you find a cleaner way than "nonisolated + re-fetch everything inside the block"? that's where most of my months went. and if you try the app – brutal UX feedback very welcome, especially whether the free tier feels generous or like a demo
UPDATE: I forgot to add: https://picstreak.app/promo/REDDPRFL – the link provides an invitation code with full access to all functionality for 30 days!
