Hi everyone,
I’ve been working on migrating my app (SwimTimes, which helps swimmers track their times) to use Core Data + CKSyncEngine with Swift 6.
After many iterations, forum searches, and experimentation, I’ve created a focused sample project that demonstrates the architecture I’m using.
The good news:
👉 I believe the crashes I was experiencing are now solved, and the sync behavior is working correctly.
👉 The demo project compiles and runs cleanly with Swift 6.
However, before adopting this as the final architecture, I’d like to ask the community (and hopefully Apple engineers) to validate a few critical points, especially regarding Swift 6 concurrency and Core Data contexts.
Architecture Overview
- Persistence layer:
Persistence.swift
sets up the Core Data stack with a main viewContext and a background context forCKSyncEngine
. - Repositories: All Core Data access is abstracted into repository classes (
UsersRepository
,SwimTimesRepository
), with async/await methods. - SyncEngine: Wraps
CKSyncEngine
, handles system fields, sync tokens, and bridging between Core Data entities and CloudKit records. - ViewModels: Marked
@MainActor
, exposing@Published
arrays for SwiftUI. They never touch Core Data directly, only via repositories. - UI: Simple SwiftUI views bound to the ViewModels.
Entities:
UserEntity
→ represents swimmers.SwimTimeEntity
→ times linked to a user (1-to-many).
Current Status
The project works and syncs across devices. But there are two open concerns I’d like validated:
-
Concurrency & Memory Safety
- Am I correctly separating
viewContext
(main/UI) vs. background context (used byCKSyncEngine
)? - Could there still be hidden risks of race conditions or memory crashes that I’m not catching?
- Am I correctly separating
-
Swift 6 Sendable Compliance
- Currently, I still need
@unchecked Sendable
in the SyncEngine and repository layers. - What is the recommended way to fully remove these workarounds and make the code safe under Swift 6’s stricter concurrency rules?
- Currently, I still need
Request
- Please review this sample project and confirm whether the concurrency model is correct.
- Suggest how I can remove the
@unchecked Sendable
annotations safely. - Any additional code improvements or best practices would also be very welcome — the intention is to share this as a community resource.
I believe once finalized, this could serve as a good reference demo for Core Data + CKSyncEngine + Swift 6, helping others migrate safely.
Environment
- iOS 18.5
- Xcode 16.4
- macOS 15.6
- Swift 6
Sample Project
Here is the full sample project on GitHub:
👉 [https://github.com/jarnaez728/coredata-cksyncengine-swift6]
Thanks a lot for your time and for any insights!
Best regards,
Javier Arnáez de Pedro