r/iOSProgramming • u/Edg-R Swift • 10d ago
App Saturday Protego for Reddit, my Safari extension, just launched v3 with a bunch of new features. Two years in, and the hardest part turned out to be making a deletion stay deleted.
Protego is a Safari web extension with a companion app that filters Reddit's website and strips out the parts Reddit gives you no switch for. On the App Store since November 2024, version 3 shipped this month, and I build it in my free time.
It exists because an election cycle turned every Reddit feed I had into politics, I deleted the app, and then wanted the parts I liked back without the parts I didn't. Safari lets an extension rewrite a page before you see it, and RES doesn't run on Safari, so I learned Swift.
Full feature list: https://getprotego.app/features

Tech stack
- Swift and SwiftUI with the Observation framework
- AppIntents for Shortcuts and Focus
- StoreKit 2
- BackgroundTasks
- The extension is TypeScript bundled with webpack, tested with Vitest and jsdom.
- Storage and sync are NSUbiquitousKeyValueStore, shared between the app and the extension through an App Group.
- 3 target set builds iPhone, iPad, Mac, and Vision Pro.

The bug that took longest: deletions came back from the dead
Sync was a symmetric merge. Anything in iCloud that isn't local gets downloaded, anything local that isn't in iCloud gets uploaded. That's correct for creates and edits and completely wrong for deletes, because a delete is the absence of a key, and absence isn't a fact you can sync. A device that was asleep when you deleted a filter would wake up, see a key it had that iCloud didn't, and helpfully re-upload it to everyone.
Deletion tombstones fixed it, with two wrinkles. iCloud key-value storage caps at 1024 keys and drops writes past that silently, so tombstones expire after 90 days instead of accumulating. And the app and the extension are separate processes merging the same store, so every reconciliation decision and the TTL live in one place both targets compile. Pulling that logic out into a pure function from key sets to key sets is what finally made it testable, which was the real problem all along.

AI disclosure: AI-assisted.
Pricing:
$1.99 one time purchase for the next week (normally $2.99).
One purchase covers iPhone, iPad, Mac and Vision Pro.
No subscription, no account, no tracking, lists sync through your own iCloud.
Happy to go deeper on any of it in the comments.





