Conflict Resolution

How TheCompanyApp handles sync conflicts in CloudKit.

Conflict Scenarios

Concurrent Edits

Example: Alice and Bob both edit the same order simultaneously (offline).

Timeline:

  1. Alice changes order.status = "Shipped" (offline)

  2. Bob changes order.status = "Cancelled" (offline)

  3. Alice's device syncs first → CloudKit accepts "Shipped"

  4. Bob's device syncs → CloudKit detects conflict

Apple's Default Resolution

NSPersistentCloudKitContainer uses last-write-wins at the property level.

Property-Level Merge:

Property
Alice's Edit
Bob's Edit
Result

status

"Shipped"

"Cancelled"

"Cancelled" (Bob's sync later)

updatedAt

2024-01-15

2024-01-15

2024-01-15 (same)

Timestamp Check: CloudKit uses modificationDate at property granularity.

Custom Conflict Handler

Not Implemented: TheCompanyApp relies on CloudKit defaults.

Future Enhancement: Implement NSPersistentCloudKitContainer.recordModificationsBlock:

User-Visible Conflicts

UpdatedAt Timestamp: Every entity has updatedAt: Date?.

Check in UI:

Conflict Minimization Patterns

1. Entity-Level Locking

Strategy: Use inUse flag.

UI: Show "Bob is editing this order" indicator.

2. Atomic Operations

Strategy: Batch related changes in one save.

3. Optimistic UI

Strategy: Show change immediately in local UI, sync in background.

If conflict occurs, CloudKit overwrites with merged result.

4. Versioning

Strategy: Store version number, increment on edit.

Conflict Detection:

Deletion Conflicts

Scenario: Alice deletes order while Bob edits same order.

Result:

  • Alice's deletion processed

  • Bob's edits rejected (record doesn't exist)

  • Bob sees error on next sync

Handling:

Merge Policies (Local)

Core Data Merge Policies: Control local conflicts (e.g., two contexts editing same object).

Current Setting:

Options:

  • NSErrorMergePolicy: Throw error on conflict

  • NSMergeByPropertyStoreTrumpMergePolicy: Server wins

  • NSMergeByPropertyObjectTrumpMergePolicy: Local wins

  • NSOverwriteMergePolicy: Overwrite all

TheCompanyApp: Uses object-trump (local wins) to preserve user edits during multi-context scenarios.

Best Practices

  1. Refresh Before Edit: Call context.refresh(order) to get latest before editing.

  2. Show Timestamps: Display updatedAt / updatedBy in detail views.

  3. Use Optimistic Locking: Check version number before saving critical edits.

  4. Communicate: Add in-app chat for teams to coordinate edits.


Related: Sync Architecture, Remote Change Handlingarrow-up-right, Troubleshooting

Last updated