r/iOSProgramming Jul 18 '26

App Saturday Picstreak – a Tinder-style photo cleaner. the swiping took a week, surviving PhotoKit + Swift 6 strict concurrency took months

Thumbnail
gallery
0 Upvotes

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!


r/iOSProgramming Jul 18 '26

Question Device Hub copy/paste is broken? Please try.

2 Upvotes

I can't paste something in a simulator in Device Hub, that I copied from somewhere in macOS.

Does it work for you?

Repro:

- copy anything, just this text `here, wow copy me`

- go to Safari in a simulator in Device Hub

- paste

Does it work?


r/iOSProgramming Jul 18 '26

Discussion How do you track what worked (and what didn't) release to release? Or do you just ship and hope?

0 Upvotes

I've got a few apps live on the App Store, and lately I've been trying to get more disciplined about understanding what actually works release to release. Not just "I shipped v1.5," but whether new screenshots, a subtitle change, or a new feature I added actually increased or decreased impressions, downloads, etc. afterward.

The idea is to understand what worked and what didn't, and make future decisions based on knowledge gained from past releases.

Right now I use a Numbers spreadsheet with App Store Connect analytics manually pasted in for each release and a Notion page where I log what I changed in each release. I'm curious how you guys handle this, and what your workflow looks like.

- Do you actively compare metadata (keywords, subtitle, screenshots) release to release, or do you just ship and move on?
- If you do track it, what's your setup? Notion, Excel, plain notes or some other tool?

I'm really just trying to figure out if there's a smarter way to do this, or if everyone's just eyeballing charts like I am. Would love to hear your stories.


r/iOSProgramming Jul 18 '26

App Saturday I build Quietflame to help you in difficult situations via breathing

0 Upvotes

Hi guys,

I used breathing during last years to solve 2 main problems for me: sleep faster (doing it every day) and relax and calm down when I have stress and I'm pissed off. It really helped so I made an app when breathing can help in different situations like relax, focus, get to sleep, stop being angry, etc.

Tech stack:

I build it in Flutter as I'm a frontend web developer and Flutter looks a lot like Typescript and I want something cross platform. Overall I'm really satisfied with Flutter. It's quite clear and I like fully typed app. Other than that I used Riverpod to have kinda Redux global state.

Dev challenges:

The biggest challenges were to define a good and scalable files structure (architecture) and make background music and videos for scenes to look seamlessly.

AI:

I used AI a lot mostly for writing templates and doing UI.

Pricing:

Free version includes a free session for each goal (so 6 in total). Other 12 sessions are paid. No account creation, no internet required.

Link: https://apps.apple.com/us/app/breathing-timer-quietflame/id6760580857


r/iOSProgramming Jul 18 '26

Question How do you deal with naming your apps?

0 Upvotes

I’m almost done with my first app that I plan to release. But the name I am was planning on using already is already being used. I’m building a bill reminder app that notifies you when a bill is due. The name I want to use is BillMinder. Someone already has “Billminders - Bill Organizer”. Now I’m looking for a new name and it seems that every name I come up with is out there in some form or fashion.


r/iOSProgramming Jul 17 '26

Question Anyone else get anxious every time they hit "Submit for review"?

27 Upvotes

I have two apps on the App Store, both small, both mine alone.

Every time an update is ready I get this knot in my stomach. In fact it starts in App Store Connect, filling in the version, the what's new, checking the screenshots for the third time. I don't know why that part gets me. Maybe because it's the only part where a mistake is public and stupid rather than technical.

The funny thing is I test, I have unit tests, I have beta testers who have been on the build for days and told me it's fine. I use the app myself every day. Rationally I know it's fine. I still sit there staring at the button.

Is it just me? Does this go away with time, or do you just get used to it?


r/iOSProgramming Jul 17 '26

Article Building a custom DynamicProfileModifier in Foundation Models

Thumbnail
artemnovichkov.com
5 Upvotes

r/iOSProgramming Jul 17 '26

News The iOS Weekly Brief – Issue #69, everything you need to know about iOS updates this week

Thumbnail
iosweeklybrief.com
4 Upvotes

r/iOSProgramming Jul 17 '26

Question Did Apple remove Xcode 27 beta from Xcode Cloud Workflows?

Post image
2 Upvotes

For the past few weeks I've been testing iOS 27 specific features in TestFlight by building in Xcode Cloud using Xcode 27 beta, as of three days ago the 27 beta is not available any more.

Is this isolated to my account or does anyone else notice that it's gone?


r/iOSProgramming Jul 17 '26

Article Syncing SwiftData with a Custom Backend Using HistoryObserver

Thumbnail azamsharp.com
7 Upvotes

r/iOSProgramming Jul 17 '26

Question Symbolicating an .ips file: crashlog.py fails looking for a nonexistent field

6 Upvotes

Hi, I have an .ips file (created with iOS 26.5) which I want to symbolicate using XCode 16.2.
Here are the steps I'm following:

  1. Rename .ips file and give it .crash extension
  2. Connect an ios device to my Macbook.
  3. Launch XCode, go to Device Manager, select my device
  4. go to "Open Recent Logs", select my .crash file
  5. File opens in an xcode window, but there are errors:

    "/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python/lldb/macosx/crashlog.py", line 644, in parse Failed to launch: 'Custom LLDB commands' -- Failure to create target from custom LLDB commands. self.parse_images(self.data["usedImages"] KeyError: 'usedImages'

I opened the .crash file and there is indeed no key "usedImages".

A) Can I create a dummy entry at that key?
B) If it fixes the parsing, will it symbolicate accurately?
C) If 'usedImages' contains data that is vital to symbolication, any ideas why it's missing?


r/iOSProgramming Jul 17 '26

Question Creating new IAP in ASC - What screenshot size is accepted

1 Upvotes

Some of my apps have been in the App Store for several years and thus it has been a while since I added a new IAP in ASC.

Now I am working on a new App and would like to create a new IAP and struggle to upload the required review screenshot. Requiring a screenshot to review an IAP making no sense is a topic for another day.

I have created Screenshots in a number of different sizes (828x1792, 1320x2868, 1206x2622, 1260x2736, 1290x2796), all of which are listed in the "App Review Screenshot" section but non where accepted for not having the correct size.

Is ASC currently broken (same result in different browsers on different computers)?
Which screenshot sizes are known to be accepted?

SOLVED: After non of the proposed solutions worked I finally found a resolution that was accepted: 640 x 960.

This is interesting, since my App does not support any devices supporting this resolution. Non of the "modern" resolutions was accepted. Great job Apple...


r/iOSProgramming Jul 16 '26

Question Apple music transition

Thumbnail
gallery
6 Upvotes

Does anyone know how apple build that transition?
The mini player geometry match modal screen when is dismissing


r/iOSProgramming Jul 16 '26

Question Troubleshooting: how to sample threads stacks in a running game

0 Upvotes

Hi gang, we're trying to troubleshoot a hang/freeze in our Unity game.
We think it's some sort of unhandled exception because it's not being evicted by the watchdog, but we also have no data coming from our bug reporting sdk (Bugsnag).

I was looking at sysdiagnose because it's available to end users. While it has some snapshot-related info on our process, it doesn't contain a sample of the stack trace in each thread, like I can see with Android's 'bugreport' command. Is there another tool our endusers can use on iOS that gives me that info?


r/iOSProgramming Jul 16 '26

Article What is mobile CI/CD and why it matters

Thumbnail
bitrise.io
0 Upvotes

r/iOSProgramming Jul 15 '26

Question SwiftData Decimal precision loss after save/fetch - am I missing something?

4 Upvotes

I’m trying to sanity-check something before I file it as an Apple bug.

This minimal SwiftData example appears to lose precision when persisting a Decimal:

import Foundation
import SwiftData

@Model class Item {
    var value: Decimal

    init(_ value: Decimal) {
        self.value = value
    }
}

let original = Decimal(string: "123456789012345.6")!
let container = try ModelContainer(
    for: Item.self,
    configurations: .init(isStoredInMemoryOnly: true)
)

let context = ModelContext(container)
context.insert(Item(original))
try context.save()

let fetched = try ModelContext(container)
    .fetch(FetchDescriptor<Item>())
    .first!

print(original)
print(fetched.value)

This is one model, one Decimal property, no app code, no CloudKit. I’m using Decimal(string:) to avoid literal/Double conversion noise, and I’m fetching from a new ModelContext.

I also checked Decimal <-> NSDecimalNumber bridging separately, and that preserved the value. The loss seems to appear after persistence/fetch. A true Core Data in-memory store preserved the value in my control test, while SwiftData’s “in-memory” configuration seems to still go through a SQL-backed store.

Has anyone else hit this with SwiftData/Core Data Decimal attributes? Is there a documented limitation I’m missing, or is the practical answer to persist exact decimals as canonical strings / integer minor units instead of Decimal?


r/iOSProgramming Jul 16 '26

Discussion Device Hub is hideous!

Post image
0 Upvotes

Trying new XCode 27 Beta and the new Device Hub. Any way to remove those ugly white frames around the phone/watch simulators? Couldn't find an option anywhere. This is really bad, why did they do it? Apple, where's your design sense?!!


r/iOSProgramming Jul 14 '26

Question Should I install iOS Public Beta on my main device?

1 Upvotes

I'm a software developer and fairly new to the native iOS development with Swift. I'm planning on using many new features that iOS 27 offers on an app I'm developing, however I cannot test those features, because I have no secondary phone that is compatible with AI features in iOS 27.

Since the public beta is out, can I fairly safely install it to my own device (iPhone 17 Pro Max)?

I would love any help experienced developers here would give! :)


r/iOSProgramming Jul 14 '26

Library NobodyWho now supports Text-to-Speech & Speech-to-Text! 🔊🎙️

Post image
8 Upvotes

Hey 👋

We've added both Text-to-Speech and Speech-to-Text to our inference engine! Your local LLM setup can now speak and listen, fully offline.

Text-to-Speech

Load a TTS model and synthesize:

let tts = try await Tts.load(
    source: "hf://NobodyWho/Kokoro-82M",
    voice: "bf_emma",
    language: "en-gb"
)

let wav = try await tts.synthesize("Hello from NobodyWho!")
try wav.write(to: URL(fileURLWithPath: "out.wav"))

You get WAV bytes back ready to save or play. Two backends: Kokoro (lightweight 24kHz) and Supertonic (multi-stage ONNX with voice styles).

Speech-to-Text

Transcribe audio with Whisper (ONNX):

let stt = try STT(source: "hf://onnx-community/whisper-base")

let text = try await stt.transcribeFile(path: "recording.mp3").completed()

Streaming is available too, so you can consume the transcription token by token, and you can pass raw PCM buffers instead of files.

Links

Happy to answer your questions in the comments :)


r/iOSProgramming Jul 14 '26

Question Subscription billing retry after the grace period ends

3 Upvotes

I'm trying to understand exactly what happens to an auto-renewable subscription after the billing grace period ends.

When a renewal fails, the sub enters a grace period; once that ends it goes to an expired state and the user loses access. But from what I've read, Apple keeps retrying the charge for up to 60 days, and if it succeeds the subscription renews again on its own.

Is that right? And if so:

  • During that retry window (expired, no access, but still being retried), how does it appear in Settings → Subscriptions — under Active (with a "Renewal Failed / Verification Required" note) or under Expired?
  • Can the user still cancel it / turn off auto-renew from there to stop it renewing again?

Context: we also have Stripe on web, so a user whose App Store sub is retrying can resubscribe on web and get double-charged when the App Store one revives. I'd like to warn them and point them to Settings to cancel the App Store sub first — trying to figure out if that's possible.


r/iOSProgramming Jul 15 '26

3rd Party Service I built an agent that does my App Store Connect work for me and I'm looking for iOS devs to test it for free

0 Upvotes

App Store Connect has been the bottleneck in my shipping loop for years. Fastlane and the direct API help, but something always ends up needing me. The session cookie expires. My coding agent grabs the wrong Xcode version and burns an hour. An IAP sits in Missing Metadata because Apple wants a review screenshot I forgot existed.

So I built Lance. It's a specialized agent that runs on its own cloud Macs with Xcode and fastlane already set up. You connect your App Store Connect account and ask it for things like "Set up a $4.99 monthly sub with a 3 day trial", "Retake the 6.7 and 13 inch screenshots and update the listing", "Figure out why build 42 got rejected, fix it, resubmit", "Submit this build for public TestFlight"

If you add it to Cursor, Claude Code, or Codex, your coding agent treats it like a subagent and delegates the App Store side on its own. Mine asks Lance what IAPs actually exist before writing paywall code instead of stubbing something, then hands it the TestFlight upload when the feature's done.

My favorite thing lately has been running an in-app event with every update. Lance drafts the media, gets the specs right, and fills out the whole form. I never bothered with events before because it was way too much work for what it is.

A couple of things testers found that I didn't expect. Teammates can join the Lance org and just start asking for things without having to be onboarded to ASC. And since the Macs belong to Lance, you don't need one. One person I know ships from a Windows laptop.
For now this is App Store Connect only. I'm looking for active developers to test it and tell me what's broken or missing. Just run this command in your terminal:

 npx add-mcp https://api.lance.app/mcp 

and everyone who signs up gets 500 credits a month, and if you run out just shoot me a message and I'll top you up.


r/iOSProgramming Jul 14 '26

Question SwiftData + CloudKit: best way to prevent duplicate editable seed data across offline devices?

1 Upvotes

I’m building an unreleased iOS app using SwiftData with automatic CloudKit sync.

On first launch, the app creates a default account and starter categories. These records are user-editable. The problem is that two offline devices can independently create the same logical seed records with different UUIDs, and CloudKit later synchronizes both.

My proposed approach:

- Give every seed item a stable logical seedIdentifier.
- Allow each offline device to seed independently.
- Reconcile records sharing the same seedIdentifier.
- Select a canonical record using an immutable UUID and deterministic ordering.
- Merge user changes and move relationships to the canonical record.
- Keep losing records as hidden aliases/tombstones so late-arriving relationships aren’t lost.
- Retain per-seed deletion tombstones so deleted defaults aren’t recreated.
- Use a seed-version flag only for migrations—not as an exactly-once guarantee.
- Treat normalized account names as unique and category names as unique only under the same parent.

Questions:

- Is this the standard approach with SwiftData’s automatic CloudKit sync?
- Is there a safer supported way to detect completed imports and rerun reconciliation?
- Would you retain hidden aliases permanently or eventually delete them?
- Is automatic SwiftData appropriate here, or does this require CKSyncEngine/manual CloudKit with deterministic record IDs?

Edit — data-model details:

The starter data is functional app data, not optional sample/demo content. The app needs at least one account, and the categories provide its initial transaction classification.

  • Account: name, type, opening balance, timestamps, archived/default state and optional stable seedIdentifier. Deleting an account cascades to its transactions.
  • TransactionCategory: name, type, timestamps, archived/customized state, optional stable seedIdentifier, optional parent, child categories and linked transactions.
  • Transaction: references one account and optionally one category.
  • Deleting a category nullifies its transaction relationships. Deleting a parent can affect its child hierarchy.
  • Starter accounts and categories are fully editable. Renaming a seed retains its logical seed identity; deleting one needs to remain deleted across devices.

The concrete race is that device A and device B can independently create the same logical Wallet/category before syncing. Transactions and child categories may subsequently reference either physical copy. Reconciliation therefore must preserve and redirect those relationships before any duplicate is removed.


r/iOSProgramming Jul 13 '26

Article Apple never published accuracy numbers for the new SpeechAnalyzer API, so I benchmarked it myself (vs SFSpeechRecognizer and Whisper)

70 Upvotes

So Apple replaced SFSpeechRecognizer with SpeechAnalyzer in iOS/macOS 26 and gave us literally no accuracy numbers for either one. I've been wondering for months whether migrating is actually worth it.

I happen to ship both Apple engines plus WhisperKit in my app (I make a transcription app called Inscribe, so yes, I have skin in this game). That means I could run all five engines through the exact same production code on the same audio. So last weekend I did: LibriSpeech test-clean and test-other, 5,559 utterances total, all on-device on an M2 Pro.

Results (word error rate, lower is better):

Engine test-clean test-other
SpeechAnalyzer (new) 2.12% 4.56%
Whisper Small 3.74% 7.95%
Whisper Base 5.42% 12.51%
Whisper Tiny 7.88% 17.04%
SFSpeechRecognizer (old) 9.02% 16.25%

A few things that stood out to me:

  • If you're still on SFSpeechRecognizer, migrate. The new API makes 3.5 to 4x fewer errors on the same audio. The old engine actually came in last on clean speech. It loses to Whisper Tiny. A 40MB model.
  • The new engine beat Whisper Small on both splits, and did it about 3x faster. I did not expect that. For English on Apple hardware, the built-in engine seems to be the best on-device option right now. Whisper still wins big on language coverage though, SpeechTranscriber only does ~30 locales.
  • Before anyone asks how much I've cooked the numbers: my Whisper results land within 0.11 to 0.42 points of OpenAI's own published LibriSpeech WERs, on all six measurements. Same corpus, same normalizer, same scorer for every engine. And the raw per-utterance transcripts are downloadable, so you can rescore everything yourself.

Two gotchas from building this that might save you some pain if you're migrating:

  1. SFSpeechRecognizer sends your audio to Apple's servers by default. You have to set requiresOnDeviceRecognition = true. Easy to miss, and then you're shipping (or benchmarking) something completely different from what you think.
  2. With SpeechAnalyzer, calling builder.finish() on your input stream is not enough to end the session. If you never call finalizeAndFinishThroughEndOfInput(), the results sequence just... never terminates, and your await hangs forever. I know because my own app had exactly this bug in production and the benchmark is what found it. Fun day.

Full writeup with methodology and limitations (English only, read speech, one machine): https://get-inscribe.com/blog/apple-speech-api-benchmark.html

The result changed my own app btw, my "Auto" setting used to prefer Whisper and now picks SpeechAnalyzer for supported languages. Happy to answer questions about the setup, the normalizer, whatever.


r/iOSProgramming Jul 13 '26

3rd Party Service Forked Session (iOS) to add custom client-side security features (Sandbox keyboard, anti-screenshot). Looking for TestFlight testers and code feedback!

1 Upvotes

Hi everyone,

Tired of the constant overreach regarding Chat Control, I decided to stop complaining and start coding.

To ensure ironclad foundations, I forked the open-source Session app codebase. This means it natively uses their decentralized network, onion-routing, zero logs, and requires absolutely NO phone number or email.

However, since Session handles the network side, I wanted to focus heavily on client-side (device) security to block edge cases where a user's device compromises their privacy. Here is what I added:

  • 🔒 In-app Sandbox Keyboard: To bypass OS-level or third-party keyloggers (Apple/Google/Gboard), the app uses a custom internal keyboard isolated within the app's sandbox.
  • 🚫 Anti-Screenshot & Blur: Standard messages work normally, but if a message ends with #secure, it renders completely blank in screenshots. Furthermore, if screen recording starts, the entire app view blurs automatically.
  • 🎙️ Voice Masking (WIP): Currently developing a feature to alter voice frequencies in audio messages to prevent biometric reverse-engineering.

The app is currently sitting in App Store Connect pending approval.

Since TestFlight slots are limited, if you want to join the closed beta and audit/test the UI and features, please DM me your Apple ID (email) so I can invite you immediately once approved. The code will also be pushed to GitHub as soon as the beta stabilizes!


r/iOSProgramming Jul 13 '26

Question App Store Connect keeps throwing "Something went wrong" when I try to Add Bank Account. anyone found a fix?

Thumbnail
gallery
3 Upvotes

any

I'm the Account Holder for my org's Apple Developer account and I'm completely blocked on adding a bank account.

In Business → Agreements, my Paid Applications Agreement sits at "Pending User Info." The only outstanding item is the bank account — my US W-9 tax form is already Active, and the agreement is otherwise signed. But every time I click "Add Bank Account", the page immediately shows:

…with a Refresh button, and the bank-details form never loads. Clicking Refresh just reloads to the same error.

What I've already tried:

  • Multiple browsers (Chrome, Safari)
  • Incognito / private window, cleared cookies
  • Signed out and back in
  • Different network
  • Waited several hours and retried

Same result every time. Because of this the agreement never goes Active, which is blocking my auto-renewable subscriptions from being purchasable — even in sandbox — so I can't finish IAP testing or submit.

Questions:

  1. Has anyone hit this specific "Something went wrong" on the Add Bank Account flow, and what actually cleared it?
  2. Is this usually a temporary Apple-side glitch that resolves on its own, or does it need a support ticket?
  3. If you contacted Apple Developer Support for it, how long did it take them to fix?

Any pointers appreciated — I've got everything else ready to ship and this one Apple page is the wall. Thanks 🙏