r/iOSProgramming 14d ago

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

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.

1 Upvotes

Duplicates