u/Efficient_Bat6894

Why I chose SwiftData over Core Data for SnapSilo (and the one thing I regret)

When I started SnapSilo I had to pick a persistence layer. CoreData is battle-tested, has years of Stack Overflow answers, and works well. SwiftData is newer, has better Swift integration, but has less documentation and some rough edges.

I went with SwiftData. Here's the reasoning and what I'd change.

Why SwiftData:

The @Model macro and @Query property wrapper are genuinely nicer to work with than NSManagedObject and NSFetchedResultsController. For a SwiftUI app, it feels like it was designed for this exact context. Less boilerplate, better integration with the view layer.

The performance for SnapSilo's use case (a few hundred to a few thousand records, mostly reads) is fine. I haven't hit any limits there.

What went wrong:

Migration. As I wrote about earlier this week, adding a non-optional property to a live model without a default value silently makes existing records inaccessible. Core Data would have thrown an error or required an explicit migration step. SwiftData just... quietly drops the rows.

There's also less documentation and fewer battle-tested patterns. When something breaks at 2am, "check the forum post from 2009 that solved this exact problem" is a resource CoreData has and SwiftData doesn't yet.

The one thing I'm still not sure about:

Complex predicates. For most queries, SwiftData works fine. But when I need to express something like "all records where field A matches X OR field B contains Y AND field C is not null" - the predicate API gets awkward. Core Data's NSPredicate handles this naturally. SwiftData's type-safe approach is cleaner for simple cases but occasionally fights you on complex ones.

Would I pick it again?

For a greenfield SwiftUI-first iOS app: yes. The ergonomics are better. Just go in knowing the migration story is fragile and documentation is sparse.

Happy to answer questions about the implementation.

reddit.com
u/Efficient_Bat6894 — 23 hours ago

Added a stats screen to SnapSilo. Here's what I learned from making a number tappable.

Small feature I shipped last week: tapping the screenshot count in the toolbar now opens a library stats sheet. Total screenshots, breakdown by tag category, storage used, oldest and newest import.

The implementation was straightforward. The interesting part was deciding what to show.

Why I built it:

SnapSilo's pitch is that it organizes your screenshots automatically. "It's organized" is a hard claim to make credible without evidence. I wanted users to be able to verify it for themselves - not trust me, just look at the numbers.

What I learned from the feature itself:

The tag breakdown was surprising even to me. I had assumed most screenshots would fall into a handful of categories (receipts, travel, UI screenshots). In practice, users have much messier libraries. A lot of "uncategorized" - items the classification pipeline couldn't confidently place. This was useful signal: the classification model needs more categories, and the fallback labeling needs work.

What I learned about feature design:

A number that does nothing is a missed opportunity. I had the count in the toolbar for weeks as an inert label. Making it tappable cost maybe two hours of work. The payoff is a feature users discover through curiosity rather than through documentation - tap a thing, see something useful.

The pattern: if you're already showing a number, think about what that number represents and whether there's more detail behind it worth surfacing.

What I'm considering adding:

A timeline view - imports per day over the last 30 days. Would help users see if their capture habit is actually changing. Probably v2 territory.

Curious if others have built similar "explain yourself" screens and what made them valuable or not.

reddit.com
u/Efficient_Bat6894 — 1 day ago

The silent data loss bug that took me two hours to find (SwiftData migration gotcha)

Sharing this because it bit me with zero warning and I couldn't find a good writeup when I searched for it.

I had SnapSilo running in production with real user data. Needed to add a new property to my SwiftData model - a timestamp for when each screenshot was imported. Seemed simple:

@Model
class Screenshot {
    var id: UUID
    var ocrText: String
    var importedAt: Date  // new field
}

Ran the app. No crash. Migration appeared to succeed. Then I noticed: all existing records were gone. Fetches returned empty arrays. The library looked empty even though the data was still there.

What was happening:

SwiftData uses lightweight migration by default. Adding a non-optional property with no default value technically succeeds at the schema level - the column gets added. But existing rows get NULL for that column, because there's nothing else to put there.

When SwiftData tries to decode those rows into your Swift model (where importedAt: Date is non-optional), it can't represent NULL as Date. Instead of throwing an error or crashing, it silently drops those records from the result set.

No error. No warning. No log message. The fetch just returns fewer results than exist in the store.

The fix:

var importedAt: Date = Date.distantPast  // existing rows get this value
// or
var importedAt: Date?  // existing rows get nil, you handle optionality at call sites

What I learned:

For a SwiftData model with production data, every new property needs to be either optional or have a default value. No exceptions. I now add this as a comment above any model property that isn't part of the original schema.

The two hours I lost were mostly to disbelief - I kept looking for something more exotic because the failure mode seemed impossible. "Fetch returns empty results but the data is there" broke my mental model.

Hopefully this saves someone else the same debugging session.

reddit.com
u/Efficient_Bat6894 — 1 day ago

How I'm getting downloads for SnapSilo with zero marketing budget (1 month in)

SnapSilo launched about a month ago. Here's an honest breakdown of what's actually driving downloads vs what I expected to work.

What I expected to work but hasn't (yet):

ASO / App Store search: I optimized the keywords, wrote a thoughtful description, got two 5-star reviews early. Organic App Store discovery is basically zero for a new app with no ratings volume. You need either a feature or existing traffic to make this work.

Product Hunt: I haven't launched there yet. Still building up enough social proof first.

What's actually working:

Posting on developer subreddits about the specific problems I solved. Not "hey check out my app" posts - actual technical writeups about how I implemented OCR, what SwiftData gotchas I hit, how I set up AppIntents with Back Tap. These drive real engagement and the occasional click-through from people who were going to Google that exact problem anyway.

Building in public on X: slower, but compounds. The posts that do well are the ones that teach something specific - a real number, a concrete decision, a failure with the fix. "I launched an app" gets nothing. "VNRecognizeTextRequest's usesLanguageCorrection makes OCR worse for screenshots" gets engagement.

Direct communities: showing up in productivity and iOS dev spaces where the problem I solved is actually relevant. This takes more time but the conversion rate is higher because the audience self-selects.

The honest numbers:

Small. Single digits of downloads most days. The occasional spike when something I post lands. The 5-star reviews help conversion rate once people find it - I just need to get more people finding it.

The pattern I'm learning: distribution for a utility app is a slow accumulation of surface area. No single channel is the answer. You just keep making the app findable in more places.

What's working for others here?

reddit.com
u/Efficient_Bat6894 — 1 day ago

The feature I underestimated: what my first App Store reviews taught me about my own app

When SnapSilo got its first real reviews, I expected feedback about the UI or the pricing. Instead, both reviewers focused on the same thing: the full-text search in screenshots.

One called it "the feature I didn't know I needed." The other asked why Apple hadn't built it into iOS natively.

What surprised me: I'd spent more development time on storage cleanup, batch delete, and the category breakdown view. Those feel like the obvious selling points for a screenshot organizer. But users latched onto OCR search immediately, even though it runs quietly in the background on import and isn't the first thing you see in the app.

The lesson I took: the feature that changes someone's mental model of what's possible lands differently than the one that saves the most time. Batch delete is useful. OCR search is a paradigm shift -- your camera roll stops being a pile of images and becomes a searchable archive. That's the thing people remember.

It changed a few things in how I think about the product:

  • Rewrote the App Store description to lead with search, not cleanup
  • Stopped treating search UI as secondary to the collection/organization views
  • Added a library stats view so users can understand what their search index actually contains (new in the latest version -- tap the item count to see a breakdown by tag)

I'm not reading too much into two reviews. But in early-stage apps, what users mention unprompted is more signal-dense than any analytics event you could track.

Anyone else had early feedback point you toward the wrong feature being your actual value prop?

reddit.com
u/Efficient_Bat6894 — 3 days ago

Why I priced SnapSilo at .99 one-time (and what I might be getting wrong)

When I was getting ready to launch SnapSilo, I spent more time on pricing than I expected.

The obvious move for a productivity app in 2026 is a subscription. Most comparable apps charge $3-5/month. That's $36-60/year vs. my $4.99 once. From a pure revenue standpoint, it's not a close call.

Here's why I didn't go that route:

SnapSilo is a tool, not a service. It runs entirely on your device. No server, no cloud, no infrastructure I need to maintain. A subscription to offset server costs makes sense. A subscription for an app that just uses your CPU and local storage feels dishonest.

$4.99 is low enough to remove the decision. For most people who screenshot things constantly, $4.99 to fix that problem is a non-decision. $4.99/month becomes "is this worth evaluating every renewal cycle?" I don't want the app's value to be questioned on a recurring basis.

I think ownership changes the relationship. When you buy a tool once, it's yours. You stop asking whether it's worth keeping. For an organizational app that you're supposed to trust with your library, that relationship matters.

What I might be wrong about:

One-time pricing means you're always chasing new customers. There's no compounding -- a subscriber from 6 months ago still contributes revenue; a one-time buyer doesn't. If I want to keep developing features, I need a steady stream of new users indefinitely.

I'm betting that word-of-mouth and App Store search can sustain that. Two unsolicited 5-star reviews in the first few weeks is a good early signal, but it's too early to know if the model works.

Would genuinely like to hear from other solo devs who've thought through this tradeoff. Did you start one-time and switch? Or go subscription from day one?

reddit.com
u/Efficient_Bat6894 — 3 days ago

Auto-importing screenshots with Personal Automations -- 3 setups that work with openAppWhenRun: false

Back Tap is the manual trigger: double-tap, one screenshot gets captured and imported. But once you have an AppIntent with openAppWhenRun: false, you can wire it into any Shortcuts Personal Automation trigger.

Here are three setups I use with SnapSilo's ImportScreenshotIntent:

1. Time-based: import every morning

Personal Automation > Time of Day > 7:00 AM > Run Shortcut > [import shortcut]

Grabs anything in Camera Roll from the past 24 hours, runs OCR, indexes everything before I've looked at my phone. Library is ready by the time I'm awake.

2. Charger automation: import when plugging in

Personal Automation > Charger > Connected > Run Shortcut > [import shortcut]

Screenshots from the day get indexed as soon as you plug in at night. Completely passive.

3. NFC tag: batch import + open cleanup view

Wrote a Shortcuts NFC tag next to my desk. One tap runs: import all recent > open SnapSilo to the storage breakdown view. Goes from "camera roll chaos" to "what do I actually want to delete" in one motion.

The critical detail: for setups 1 and 2, openAppWhenRun: false means the automation runs entirely in the background -- no modal, no app switch, no notification (unless you add one deliberately). The import just happens.

For setup 3, if you want the app to actually open to the cleanup view, you'd flip to openAppWhenRun: true on a second intent, or just use the "Open App" Shortcuts action at the end of the chain.

Any Personal Automation that supports "Run Shortcut" as an action works. Which means pretty much any trigger in iOS.

reddit.com
u/Efficient_Bat6894 — 4 days ago

AppIntents + 'Take Screenshot': how image data actually flows from Shortcuts into your custom intent

Been posting about SnapSilo's Back Tap import system. Got some questions about the technical side -- specifically how the image data from the Shortcuts "Take Screenshot" action flows into a custom AppIntent.

Here's what I figured out after some trial and error.

The parameter type that actually works with "Take Screenshot":

@Parameter(title: "Image") var image: IntentFile

This is the key thing nobody documents. If you use @Parameter var photo: PHAsset, Shortcuts won't wire the "Take Screenshot" output to it -- that bridge only works with the Photos picker action, not screenshot capture. With IntentFile, you get raw Data directly. No Photos library permission needed for the image itself.

Background processing with Vision framework:

When openAppWhenRun: false, your perform() runs in the background with no UI. Vision's VNRecognizeTextRequest is callback-based, so you need to bridge it to Swift Concurrency:

func perform() async throws -> some IntentResult {
    guard let data = image.data,
          let cgImage = UIImage(data: data)?.cgImage else {
        throw IntentError.invalidImage
    }
    let text = try await recognizeText(in: cgImage)
    // store in SwiftData, classify, done
    return .result()
}

This runs OCR and classification entirely in background -- app never opens.

The delete-from-Photos step:

The "delete from Photos" action lives in the Shortcut chain, not inside the AppIntent. When you receive the image via IntentFile, you don't have the PHAsset identifier, so deletion needs to be a separate Shortcuts action after your intent returns.

Full chain: Take Screenshot > ImportScreenshotIntent > (optional) Delete Photo

Works on a locked phone as long as permissions were granted at least once while unlocked. The intent itself has no UI so there's nothing to block it.

Anyone building something similar with AppIntents and Shortcuts -- happy to answer questions about what worked and what didn't.

reddit.com
u/Efficient_Bat6894 — 4 days ago

Step-by-step: setting up iPhone Back Tap to silently capture + OCR-index screenshots without opening any app

Been getting questions about the exact setup flow for the Back Tap capture in SnapSilo, so here's the full guide.

What it does: double-tap the back of your iPhone, a screenshot is taken, imported into SnapSilo, OCR-indexed and auto-tagged, optionally deleted from Photos - all without the app ever appearing on screen.

Setup steps:

  1. Install SnapSilo and open it once to complete onboarding
  2. Import the shortcut: https://www.icloud.com/shortcuts/8343d5a4436445009263a26a4ccd07e9
  3. Go to Settings > Accessibility > Touch > Back Tap
  4. Choose Double Tap (or Triple Tap)
  5. Scroll to the bottom under Shortcuts - select the SnapSilo shortcut

That's it. No configuration needed beyond choosing whether to delete from Photos immediately (there's a toggle in the shortcut itself).

What happens when you double-tap:

The Shortcuts runtime wakes in the background, takes a screenshot, and passes it to SnapSilo's ImportScreenshotIntent. The intent runs Vision OCR and two-pass classification (keyword match on extracted text, image classification as fallback). The result gets stored in the local SwiftData database. No network call, no foreground launch.

Search works immediately after - type any word that appeared in the screenshot and SnapSilo finds it.

Things worth knowing:

  • Back Tap sometimes conflicts with cases that cover the Apple logo - a thinner case or no case works better
  • Triple Tap is more reliable if you find yourself triggering it accidentally
  • The shortcut works even when the phone is locked if you have the appropriate Shortcuts permissions set

Happy to answer questions about the AppIntents side if anyone is building something similar.

reddit.com
u/Efficient_Bat6894 — 5 days ago

How I used AppIntents + Back Tap to import screenshots silently in the background (openAppWhenRun: false is the key)

The Back Tap capture in my app SnapSilo isn't a native Back Tap API. iOS doesn't expose one to AppIntents directly. Here's how it works, since I've seen people ask about background execution patterns.

The setup:

  1. iOS Accessibility Back Tap triggers a Shortcut
  2. The Shortcut calls a custom AppIntent (ImportScreenshotIntent) declared with openAppWhenRun: false
  3. The intent receives the screenshot, runs Vision framework OCR + classification, and saves to the app's local library
  4. Optional: the intent deletes the screenshot from Photos after importing

The key is openAppWhenRun: false. Without it, the app launches in the foreground on every double-tap. With it, the whole chain runs silently without bringing the app forward.

The intent receives a UIImage from the Shortcut's "Take Screenshot" action directly, so no file path handling needed. The Shortcut bridges the Back Tap trigger and your AppIntent.

What this enables: any Shortcuts trigger (Back Tap, Automation, Focus mode change) can kick off background AppIntent execution without a full app launch. Back Tap is the most satisfying trigger because it feels hardware-level, even though it's Shortcuts under the hood.

The shortcut is publicly available if you want to install and poke around: https://www.icloud.com/shortcuts/8343d5a4436445009263a26a4ccd07e9

Happy to answer questions about the AppIntents side if anyone's building something similar.

reddit.com
u/Efficient_Bat6894 — 6 days ago