Hi,
I'm having trouble implementing iCloud Drive in my app. I've already taken the obvious steps, including enabling iCloud Documents in Xcode and selecting a container. This container is correctly specified in my code, and in theory, everything should work.
The data generated by my app should be saved to iCloud Drive in addition to local storage. The data does get stored in the Files app, but the automatic syncing to iCloud Drive doesn’t work as expected.
I’ve also considered updating my .entitlements file.
Since I’m at a loss, I’m reaching out for help maybe I’ve overlooked something important that's causing it not to work. If anyone has an idea, please let me know.
Thanks in advance!
iCloud & Data
RSS for tagLearn how to integrate your app with iCloud and data frameworks for effective data storage
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
Hi all,
I’m encountering a consistent issue with SwiftData on watchOS when using CloudKit sync. After enabling:
let config = ModelConfiguration(schema: schema, cloudKitDatabase: .automatic)
…the app terminates ~30–60 seconds into a WKExtendedRuntimeSession. This happens specifically when:
Always-On Display is OFF
The iPhone is disconnected or in Airplane Mode
The app is running in a WKExtendedRuntimeSession (e.g., used for meditation tracking)
The Xcode logs show a warning:
Background Task ("CoreData: CloudKit Setup"), was created over 30 seconds ago. In applications running in the background, this creates a risk of termination.
It appears CloudKit sync setup is being triggered automatically and flagged by the system as an unmanaged long-running task, leading to termination.
Workaround:
Switching to:
let config = ModelConfiguration(schema: schema, cloudKitDatabase: .none)
…prevents the issue entirely — no background task warning, no crash.
Feedback ID submitted: FB17685611
Just wanted to check if others have seen this behavior or found alternative solutions. It seems like something Apple may need to address in SwiftData’s CloudKit handling on watchOS.
Topic:
App & System Services
SubTopic:
iCloud & Data
Tags:
CloudKit
watchOS
Background Tasks
SwiftData
There's some logic in my app that first checks to see if a specific CloudKit record zone exists. If it doesn't, it creates the zone, and then my application continues on with its work.
The way I've implemented this right now is by catching the zoneNotFound error when I call CKDatabase#recordZone(for:) (docs) and creating the zone when that happens:
do {
try await db.recordZone(for: zoneID)
} catch let ckError as CKError
where [.zoneNotFound, .userDeletedZone].contains(ckError.code)
{
// createZone is a helper function
try await createZone(zoneID: zoneID, context: context)
}
This works great, but every time I do this, an error is logged in CloudKit Console, which creates a lot of noise and makes it harder to see real errors.
Is there a way to do this without explicitly triggering a CloudKit error?
I just found CKDatabase#recordZones(for:) (docs), which seems like it returns an empty array instead of throwing an error if the zone doesn't exist.
Will calling that and looking for a non-empty array work just as well, but without logging lots of errors in the console?
What is the best way to switch between Core Data Persistent Stores?
My use case is that I have a multi-user app that stores thousands of data items unique to each user. To me, having Persistent Stores for each user seems like the best design to keep their data separate and private. (If anyone believes that storing the data for all users in one Persistent Store is a better design, I'd appreciate hearing from them.)
Customers might switch users 5 to 10 times a day. Switching users must be fast, say a second or two at most.
In the future, is there any plans to have AppMigrationKit for macOS-Windows cross transfers (or Linux, ChromeOS, HarmonyOS NEXT, etc)? Additionally, will the migration framework remain just iOS <-> Android or will it extend to Windows tablets, ChromeOS Tablets, HarmonyOS NEXT, KaiOS, Series 30+, Linux mobile, etc.
Topic:
App & System Services
SubTopic:
iCloud & Data
Good Morning I am building a app that uses cloudkit and am trying to find our the app limits allowed
I have been trying to find out the app limits to my app when released into the app store, I understand that in the public database the app worldwide can use 200g of bandwidth free per month. What happens after that? is it throttled? is there a pricing structure for overages? thanks
Hi everyone,
I am a beginner in iOS/Swift programming. I'm trying to develop a mobile application that allows to mount a network drive in the iphone Files application via the WebDav protocol.
I saw on the internet that WebDav is no longer implemented in iOS because considered deprecated by apple.
To accomplish this task, I decided to separate responsibilities as follows:
Framework:
WebDav (responsible for communication with the WebDav server)
FileProviderExtension:
FileBridge (Responsible for bridging the gap between the WebDav Framework and the iOS Files app)
Main App
I also have an AppGroup that includes the main application and the fileproviderextension
Initially, to measure the feasibility and complexity of this task, I'd like to make a simplistic version that simply displays the files on my drive in the Files app, without necessarily being able to interact with them.
FileProviderExtension.swift:
import FileProvider
import WebDav
class FileProviderExtension: NSObject, NSFileProviderReplicatedExtension {
private var webDavService: WebDavService?
required init(domain: NSFileProviderDomain)
{
super.init()
self.webDavService = WebDavService(baseURL: URL(string: "https://www.mydrive.com/drive")!)
}
func invalidate() {
// TODO: cleanup any resources
}
func item(for identifier: NSFileProviderItemIdentifier,
request: NSFileProviderRequest,
completionHandler: @escaping (NSFileProviderItem?, Error?) -> Void) -> Progress {
let progress = Progress(totalUnitCount: 1)
Task {
do {
if let items = try await webDavService?.propfind(path: identifier.rawValue, depth: 1),
let item = items.first(where: { $0.itemIdentifier == identifier }) {
completionHandler(item, nil)
} else {
completionHandler(nil, NSError(domain: NSCocoaErrorDomain,
code: NSFileNoSuchFileError,
userInfo: nil))
}
} catch {
completionHandler(nil, error)
}
}
return progress
}
func fetchContents(for itemIdentifier: NSFileProviderItemIdentifier,
version requestedVersion: NSFileProviderItemVersion?,
request: NSFileProviderRequest,
completionHandler: @escaping (URL?, NSFileProviderItem?, Error?) -> Void) -> Progress {
let progress = Progress(totalUnitCount: 1)
Task {
do {
guard let service = webDavService else {
throw WebDavError.invalidResponse
}
let data = try await service.get(fileAt: itemIdentifier.rawValue)
let tempURL = FileManager.default.temporaryDirectory.appendingPathComponent(itemIdentifier.rawValue)
try data.write(to: tempURL)
completionHandler(tempURL, nil, nil)
} catch {
completionHandler(nil, nil, error)
}
}
return progress
}
func createItem(basedOn itemTemplate: NSFileProviderItem, fields: NSFileProviderItemFields, contents url: URL?, options: NSFileProviderCreateItemOptions = [], request: NSFileProviderRequest, completionHandler: @escaping (NSFileProviderItem?, NSFileProviderItemFields, Bool, Error?) -> Void) -> Progress {
// TODO: a new item was created on disk, process the item's creation
completionHandler(itemTemplate, [], false, nil)
return Progress()
}
func modifyItem(_ item: NSFileProviderItem, baseVersion version: NSFileProviderItemVersion, changedFields: NSFileProviderItemFields, contents newContents: URL?, options: NSFileProviderModifyItemOptions = [], request: NSFileProviderRequest, completionHandler: @escaping (NSFileProviderItem?, NSFileProviderItemFields, Bool, Error?) -> Void) -> Progress {
// TODO: an item was modified on disk, process the item's modification
completionHandler(nil, [], false, NSError(domain: NSCocoaErrorDomain, code: NSFeatureUnsupportedError, userInfo:[:]))
return Progress()
}
func deleteItem(identifier: NSFileProviderItemIdentifier, baseVersion version: NSFileProviderItemVersion, options: NSFileProviderDeleteItemOptions = [], request: NSFileProviderRequest, completionHandler: @escaping (Error?) -> Void) -> Progress {
// TODO: an item was deleted on disk, process the item's deletion
completionHandler(NSError(domain: NSCocoaErrorDomain, code: NSFeatureUnsupportedError, userInfo:[:]))
return Progress()
}
func enumerator(for containerItemIdentifier: NSFileProviderItemIdentifier,
request: NSFileProviderRequest) throws -> NSFileProviderEnumerator {
return FileProviderEnumerator(enumeratedItemIdentifier: containerItemIdentifier,
service: webDavService)
}
}
Here's the code I use to initialize my domain in the main app files:
fileprivate func registerFileProviderDomain() {
let domainIdentifier = NSFileProviderDomainIdentifier("FileProviderExtension Bundle Identifier")
let domain = NSFileProviderDomain(identifier: domainIdentifier,
displayName: "My Drive")
NSFileProviderManager.add(domain) { error in
NSFileProviderManager.add(domain) { error in
if let error = error {
print("Error cannot add domain file provider : \(error.localizedDescription)")
} else {
print("Success domain file provider added")
}
}
}
I can't get rid of the Error :
Error cannot add domain file provider : The operation couldn’t be completed. Invalid argument.
I don't know what I'm missing
Please help me understand
I haven't been able to find a definitive answer to this online. Is NSUbiquitousKeyValueStore end-to-end encrypted with Advanced Data Protection turned on? It’s not specifically called out here https://support.apple.com/en-us/102651.
Topic:
App & System Services
SubTopic:
iCloud & Data
If I use <FetchRequest.returnsDistinctResults> with unique "identifier" property, and there happened to be multiple NSManagedObjects in Core Data that contains the same "identifier", does the FetchRequest retrieve the latest modified/created object?
Is there a way to define the <FetchRequest.returnsDistinctResults> logic to be based on another property (e.g. "creationDate" / "modifiedDate") and the ascension order?
Topic:
App & System Services
SubTopic:
iCloud & Data
What is the idiomatic way to use a ModelContext in a document based SwiftData app from a background thread?
The relevant DocumentGroup initializers do not give us direct access to a ModelContainer, only to a ModelContext.
Is it safe to take its modelContext.container and pass it around (for creating a ModelContext on it on a background thread) or to construct a ModelActor with it? Is it safe to e.g. put a ModelActor so created into the environment of the root view of the window and execute various async data operations on it in Tasks throughout the app, as long as these are dispatched from within the window whose root view's ModelContext was used for getting the ModelContainer?
Trying to support undo & redo in an app that utilizes Swift Data and as with anything other than provided simplistic Apple demo examples the experience is not great.
The problem:
Im trying to build functionality that allows users to add items to an item group, where item and item group have a many-to-many relationship e.g. item group can hold many items and items can appear in multiple groups.
When trying to do so with relatively simple setup of either adding or removing item group from items relationship array, I am pretty consistently met with a hard crash after performing undo & redo. Sometimes it works the first few undo & redos but 95% of the time would crash on the first one.
Could not cast value of type 'Swift.Optional<Any>' (0x20a676be0) to 'Swift.Array<App.CodableStructModel>' (0x207a2bc08).
Where CodableStructModel is a Codable Value type inside Item.
Adding and removing this relationship should be undoable & redoable as typical for Mac interaction and is "supported" by SwiftData by default, meaning that the developer has to actively either wholly opt out of undo support in their modelContainer setup or do it on a per action scale with the only thing I know of:
modelContext.processPendingChanges()
modelContext.undoManager?.disableUndoRegistration()
.....
modelContext.processPendingChanges()
modelContext.undoManager?.enableUndoRegistration()
General rant on SwiftData:
Random crashes, inconsistencies, random cryptic errors thrown by the debugger and general lack of production level stability.
Each update breaks something new and there is very little guidance and communication from the Swift Data team on how to adapt and more importantly consideration for developers that have adopted Swift Data.
If SwiftData is not ready for production, it would go a long way to clearly communicate that and mark it as Beta product.
If an app is using top-level models, meaning they exist outside the VersionedSchema enum, is it safe to keep them outside of the VersionedSchema enum and use a migration plan for simple migrations. Moving the models within the VersionedSchema enum I believe would change the identity of the models and result in data being lost, although correct me if I'm wrong in that statement.
The need presently is just to add another variable to the model and then set that variable within the init function:
var updateId = UUID()
The app is presently in TestFlight although I'd like to preserve data for users that are currently using the app.
The data within SwiftData is synchronized with CloudKit and so I'd also like to avoid any impact to synchronization.
Any thoughts on this would be greatly appreciated.
I'm experiencing a critical issue with SwiftData custom migrations where objects created during migration appear to be inserted successfully but aren't persisted or found by queries after migration completes. The migration logs show objects being created, but subsequent queries return zero results.
I'm migrating from schema version V2 to V2_5, which involves:
Renaming Person class to GroupData
Keeping the same data structure but changing the class name while keeping the old class.
Using a custom migration stage to copy data from old to new schema
Below is an extract of my two schema and migration plan:
Environment:
Xcode 16.0,
iOS 18.0,
Swift 6.0
SchemaV2
enum LinkMapV2: VersionedSchema {
static let versionIdentifier: Schema.Version = .init(2, 0, 0)
static var models: [any PersistentModel.Type] {
[AnnotationData.self, Person.self, History.self]
}
@Model
final class Person {
@Attribute(.unique) var id: UUID
var name: String
var photo: String
var requirement: String
var statue: Bool
var annotationId: UUID?
var number: Int = 0
init(id: UUID = UUID(), name: String = "", photo: String = "", requirement: String = "", status: Bool = false, annotationId: UUID? = nil, number: Int = 0) {
self.id = id
self.name = name
self.photo = photo
self.requirement = requirement
self.statue = status
self.annotationId = annotationId
self.number = number
}
}
}
Schema V2_5
static let versionIdentifier: Schema.Version = .init(2, 5, 0)
static var models: [any PersistentModel.Type] {
[AnnotationData.self, Person.self, GroupData.self, History.self]
}
// Keep the old Person model for migration
@Model
final class Person {
@Attribute(.unique) var id: UUID
var name: String
var photo: String
var requirement: String
var statue: Bool
var annotationId: UUID?
var number: Int = 0
init(id: UUID = UUID(), name: String = "", photo: String = "", requirement: String = "", status: Bool = false, annotationId: UUID? = nil, number: Int = 0) {
self.id = id
self.name = name
self.photo = photo
self.requirement = requirement
self.statue = status
self.annotationId = annotationId
self.number = number
}
}
// Add the new GroupData model that mirrors Person
@Model
final class GroupData {
@Attribute(.unique) var id: UUID
var name: String
var photo: String
var requirement: String
var status: Bool
var annotationId: UUID?
var number: Int = 0
init(id: UUID = UUID(), name: String = "", photo: String = "", requirement: String = "", status: Bool = false, annotationId: UUID? = nil, number: Int = 0) {
self.id = id
self.name = name
self.photo = photo
self.requirement = requirement
self.status = status
self.annotationId = annotationId
self.number = number
}
}
}
Migration Plan
static let migrationV2toV2_5 = MigrationStage.custom(
fromVersion: LinkMapV2.self,
toVersion: LinkMapV2_5.self,
willMigrate: { context in
do {
let persons = try context.fetch(FetchDescriptor<LinkMapV2.Person>())
print("=== MIGRATION STARTED ===")
print("Found \(persons.count) Person objects to migrate")
guard !persons.isEmpty else {
print("No Person data requires migration")
return
}
for person in persons {
print("Migrating Person: '\(person.name)' with ID: \(person.id)")
let newGroup = LinkMapV2_5.GroupData(
id: person.id, // Keep the same ID
name: person.name,
photo: person.photo,
requirement: person.requirement,
status: person.statue,
annotationId: person.annotationId,
number: person.number
)
context.insert(newGroup)
print("Inserted new GroupData: '\(newGroup.name)'")
// Don't delete the old Person yet to avoid issues
// context.delete(person)
}
try context.save()
print("=== MIGRATION COMPLETED ===")
print("Successfully migrated \(persons.count) Person objects to GroupData")
} catch {
print("=== MIGRATION ERROR ===")
print("Migration failed with error: \(error)")
}
},
didMigrate: { context in
do {
// Verify migration in didMigrate phase
let groups = try context.fetch(FetchDescriptor<LinkMapV2_5.GroupData>())
let oldPersons = try context.fetch(FetchDescriptor<LinkMapV2_5.Person>())
print("=== MIGRATION VERIFICATION ===")
print("New GroupData count: \(groups.count)")
print("Remaining Person count: \(oldPersons.count)")
// Now delete the old Person objects
for person in oldPersons {
context.delete(person)
}
if !oldPersons.isEmpty {
try context.save()
print("Cleaned up \(oldPersons.count) old Person objects")
}
// Print all migrated groups for debugging
for group in groups {
print("Migrated Group: '\(group.name)', Status: \(group.status), Number: \(group.number)")
}
} catch {
print("Migration verification error: \(error)")
}
}
)
And I've attached console output below:
Console Output
Description:
I'm experiencing a critical issue with SwiftData custom migrations where objects created during migration appear to be inserted successfully but aren't persisted or found by queries after migration completes. The migration logs show objects being created, but subsequent queries return zero results.
Problem Details:
I'm migrating from schema version V2 to V3, which involves:
Renaming Person class to GroupData
Keeping the same data structure but changing the class name
Using a custom migration stage to copy data from old to new schema
Migration Code:
swift
static let migrationV2toV3 = MigrationStage.custom(
fromVersion: LinkMapV2.self,
toVersion: LinkMapV3.self,
willMigrate: { context in
do {
let persons = try context.fetch(FetchDescriptor<LinkMapV2.Person>())
print("Found (persons.count) Person objects to migrate") // ✅ Shows 11 objects
for person in persons {
let newGroup = LinkMapV3.GroupData(
id: person.id, // Same UUID
name: person.name,
// ... other properties
)
context.insert(newGroup)
print("Inserted GroupData: '\(newGroup.name)'") // ✅ Confirms insertion
}
try context.save() // ✅ No error thrown
print("Successfully migrated \(persons.count) objects") // ✅ Confirms save
} catch {
print("Migration error: \(error)")
}
},
didMigrate: { context in
do {
let groups = try context.fetch(FetchDescriptor<LinkMapV3.GroupData>())
print("Final GroupData count: \(groups.count)") // ❌ Shows 0 objects!
} catch {
print("Verification error: \(error)")
}
}
)
Console Output:
text
=== MIGRATION STARTED ===
Found 11 Person objects to migrate
Migrating Person: 'Riverside of pipewall' with ID: 7A08C633-4467-4F52-AF0B-579545BA88D0
Inserted new GroupData: 'Riverside of pipewall'
... (all 11 objects processed) ...
=== MIGRATION COMPLETED ===
Successfully migrated 11 Person objects to GroupData
=== MIGRATION VERIFICATION ===
New GroupData count: 0 // ❌ PROBLEM: No objects found!
What I've Tried:
Multiple context approaches:
Using the provided migration context
Creating a new background context with ModelContext(context.container)
Using context.performAndWait for thread safety
Different save strategies:
Calling try context.save() after insertions
Letting SwiftData handle saving automatically
Multiple save calls at different points
Verification methods:
Checking in didMigrate closure
Checking in app's ContentView after migration completes
Using both @Query and manual FetchDescriptor
Schema variations:
Direct V2→V3 migration
Intermediate V2.5 schema with both classes
Lightweight migration with @Attribute(originalName:)
Current Behavior:
Migration runs without errors
Objects appear to be inserted successfully
context.save() completes without throwing errors
But queries in didMigrate and post-migration return empty results
The objects seem to exist in a temporary state that doesn't persist
Expected Behavior:
Objects created during migration should be persisted and queryable
Post-migration queries should return the migrated objects
Data should be available in the main app after migration completes
Environment:
Xcode 16.0+
iOS 18.0+
SwiftData
Swift 6.0+
Key Questions:
Is there a specific way migration contexts should be handled for data to persist?
Are there known issues with object persistence in custom migrations?
Should we be using a different approach for class renaming migrations?
Is there a way to verify that objects are actually being written to the persistent store?
The migration appears to work perfectly until the verification step, where all created objects seem to vanish. Any guidance would be greatly appreciated!
Additional Context from my investigation:
I've noticed these warning messages during migration that might be relevant:
text
SwiftData.ModelContext: Unbinding from the main queue. This context was instantiated on the main queue but is being used off it.
error: Persistent History (76) has to be truncated due to the following entities being removed: (Person)
This suggests there might be threading or context lifecycle issues affecting persistence.
Let me know if you need any additional information about my setup or migration configuration!
I have an app which uses ubiquitous containers and files in them to share data between devices. It's a bit unusual in that it indexes files in directories the user grants access to, which may or may not exist on a second device - those files are identified by SHA-1 hash. So a second device scanning before iCloud data has fully sync'd can create duplicate references which lead to an unpleasant user experience.
To solve this, I store a small binary index in the root of the ubiquitous file container of the shared data, containing all of the known hashes, and as the user proceeds through the onboarding process, a background thread is attempting to "prime" the ubiquitous container by calling FileManager.default.startDownloadingUbiquitousItemAt() for each expected folder and file in a sane order.
This likely creates a situation not anticipated by the iOS/iCloud integration's design, as it means my app has a sort of precognition of files it should not yet know about.
In the common case, it works, but there is a corner case where iCloud sync has just begun, and very, very little metadata is available (the common case, however, in an emulator), in which two issues come up:
I/O may hang indefinitely, trying to read a file as it is arriving. This one I can work around by running the I/O in a thread created with the POSIX pthread_create and using pthread_cancel to kill it after a timeout.
Attempts to call FileManager.default.startDownloadingUbiquitousItemAt() fails with an error Error Domain=NSCocoaErrorDomain Code=257 "The file couldn’t be opened because you don’t have permission to view it.". The permissions aspect of it is nonsense, but I can believe there's no applicable "sort of exists, sort of doesn't" error code to use and someone punted. The problem is that this same error will be thrown on any attempt to access that file for the life of the application - a restart is required to make it usable.
Clearly, the error or the hallucinated permission failure is cached somewhere in the bowels of iOS's FileManager. I was hoping startAccessingSecurityScopedResource() would allow me to bypass such a cache, as it does with URL.resourceValues() returning stale file sizes and last modified times. But it does not.
Is there some way to clear this state without popping up a UI with an Exit button (not exactly the desired iOS user experience)?
Topic:
App & System Services
SubTopic:
iCloud & Data
Tags:
Foundation
Files and Storage
iOS
iCloud Drive
Hi,
I'm getting a very odd error log in my SwiftData setup for an iOS app. It is implemented to support schema migration. When starting the app, it simply prints the following log twice (seems to be dependent on how many migration steps, I have two steps in my sample code):
CoreData: error: Attempting to retrieve an NSManagedObjectModel version checksum while the model is still editable. This may result in an unstable verison checksum. Add model to NSPersistentStoreCoordinator and try again.
(Yes there is a mistyped word "verison", this is exactly the log)
The code actually fully works. But I have neither CloudKit configured, nor is this app in Production yet. I'm still just developing.
Here is the setup and code to reproduce the issue.
Development mac version: macOS 15.5
XCode version: 16.4
iOS Simulator version: 18.5
Real iPhone version: 18.5
Project name: SwiftDataDebugApp
SwiftDataDebugApp.swift:
import SwiftUI
import SwiftData
@main
struct SwiftDataDebugApp: App {
var sharedModelContainer: ModelContainer = {
let schema = Schema([
Item.self,
])
let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false, allowsSave: true)
do {
return try ModelContainer(for: schema, migrationPlan: ModelMigraitonPlan.self, configurations: [modelConfiguration])
} catch {
fatalError("Could not create ModelContainer: \(error)")
}
}()
var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer(sharedModelContainer)
}
}
Item.swift:
import Foundation
import SwiftData
typealias Item = ModelSchemaV2_0_0.Item
enum ModelSchemaV1_0_0: VersionedSchema {
static var versionIdentifier = Schema.Version(1, 0, 0)
static var models: [any PersistentModel.Type] {
[Item.self]
}
@Model
final class Item {
var timestamp: Date
init(timestamp: Date) {
self.timestamp = timestamp
}
}
}
enum ModelSchemaV2_0_0: VersionedSchema {
static var versionIdentifier = Schema.Version(2, 0, 0)
static var models: [any PersistentModel.Type] {
[Item.self]
}
@Model
final class Item {
var timestamp: Date
var tags: [Tag] = []
init(timestamp: Date, tags: [Tag]) {
self.timestamp = timestamp
self.tags = tags
}
}
}
enum ModelMigraitonPlan: SchemaMigrationPlan {
static var schemas: [any VersionedSchema.Type] {
[ModelSchemaV1_0_0.self]
}
static var stages: [MigrationStage] {
[migrationV1_0_0toV2_0_0]
}
static let migrationV1_0_0toV2_0_0 = MigrationStage.custom(
fromVersion: ModelSchemaV1_0_0.self,
toVersion: ModelSchemaV2_0_0.self,
willMigrate: nil,
didMigrate: { context in
let items = try context.fetch(FetchDescriptor<ModelSchemaV2_0_0.Item>())
for item in items {
item.tags = Array(repeating: "abc", count: Int.random(in: 0...3)).map({ Tag(value: $0) })
}
try context.save()
}
)
}
Tag.swift:
import Foundation
struct Tag: Codable, Hashable, Comparable {
var value: String
init(value: String) {
self.value = value
}
static func < (lhs: Tag, rhs: Tag) -> Bool {
return lhs.value < rhs.value
}
static func == (lhs: Tag, rhs: Tag) -> Bool {
return lhs.value == rhs.value
}
func hash(into hasher: inout Hasher) {
hasher.combine(value)
}
}
ContentView.swift:
import SwiftUI
import SwiftData
struct ContentView: View {
@Environment(\.modelContext) private var modelContext
@Query private var items: [Item]
var body: some View {
VStack {
List {
ForEach(items) { item in
VStack(alignment: .leading) {
Text(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))
HStack {
ForEach(item.tags, id: \.hashValue) { tag in
Text("\(tag.value)")
}
}
}
}
.onDelete(perform: deleteItems)
}
Button("Add") {
addItem()
}
.padding(.top)
}
}
private func addItem() {
withAnimation {
let newItem = Item(timestamp: Date(), tags: [Tag(value: "Hi")])
modelContext.insert(newItem)
}
do {
try modelContext.save()
} catch {
print("Error saving add: \(error.localizedDescription)")
}
}
private func deleteItems(offsets: IndexSet) {
withAnimation {
for index in offsets {
modelContext.delete(items[index])
}
}
do {
try modelContext.save()
} catch {
print("Error saving delete: \(error.localizedDescription)")
}
}
}
#Preview {
ContentView()
.modelContainer(for: Item.self, inMemory: true)
}
I hope someone can help, couldn't find anything related to this log at all.
Hello Apple Team,
We are looking at developing an iOS feature on our current development that stores user-generated images as CKAssets in the public CloudKit database, with access control enforced by our app’s own logic (not CloudKit Sharing as that has a limit of 100 shares per device). Each story or post is a public record, and users only see content based on buddy relationships handled within the app.
We’d like to confirm that this pattern is consistent with Apple’s best practices for social features. Specifically:
Is it acceptable to store user-uploaded CKAssets in the public CloudKit database, as long as access visibility is enforced by the app?
Are there any performance or quota limitations (e.g., storage, bandwidth, or user sync limits) that apply to CKAssets in the public database when used at scale?
Would CloudKit Sharing be recommended instead, even if we don’t require user-to-user sharing invitations?
For App Review, is this model (public CKAssets + app-enforced access control) compliant with Apple’s data and security expectations?
Are there any caching or bandwidth optimization guidelines for handling image-heavy public CKAsset data in CloudKit?
Thanks again for your time
I have the following struct doing some simple tasks, running a network request and then saving items to Core Data.
Per Xcode 26's new default settings (onisolated(nonsending) & defaultIsolation set to MainActor), the struct and its functions run on the main actor, which works fine and I can even safely omit the context.perform call because of it, which is great.
struct DataHandler {
func importGames(withIDs ids: [Int]) async throws {
...
let context = PersistenceController.shared.container.viewContext
for game in games {
let newGame = GYGame(context: context)
newGame.id = UUID()
}
try context.save()
}
}
Now, I want to run this in a background thread to increase performance and responsiveness. So I followed this session (https://developer.apple.com/videos/play/wwdc2025/270) and believe the solution is to mark the struct as nonisolated and the function itself as @concurrent.
The function now works on a background thread, but I receive a crash: _dispatch_assert_queue_fail. This happens whether I wrap the Core Data calls with context.perform or not. Alongside that I get a few new warnings which I have no idea how to work around.
So, what am I doing wrong here? What's the correct way to solve this simple use case with Swift 6's new concurrency stuff and the default main actor isolation in Xcode 26?
Curiously enough, when setting onisolated(nonsending) to false & defaultIsolation to non isolating, mimicking the previous behavior, the function works without crashing.
nonisolated
struct DataHandler {
@concurrent
func importGames(withIDs ids: [Int]) async throws {
...
let context = await PersistenceController.shared.container.newBackgroundContext()
for game in games {
let newGame = GYGame(context: context)
newGame.id = UUID() // Main actor-isolated property 'id' can not be mutated from a nonisolated context; this is an error in the Swift 6 language mode
}
try context.save()
}
}
We are trying to solve for the following condition with SwiftData + CloudKit:
Lots of data in CloudKit
Perform "app-reset" to clear data & App settings and start fresh.
Reset data models with try modelContext.delete(model:_) myModel.count() confirms local deletion (0 records); but iCloud Console shows expectedly slow process to delete.
Old CloudKit data is returning during the On Boarding process.
Questions:
• Would making a new iCloud Zone for each reset work around this, as the new zone would be empty? We're having trouble finding details about how to do this with SwiftData.
• Would CKSyncEngine have a benefit over the default SwiftData methods?
Open to hearing if anyone has experienced a similar challenge and how you worked around it!
Hello Apple Team,
We’re building a CloudKit-enabled Core Data app and would like clarification on the behavior and performance characteristics of Binary Data attributes with “Allows External Storage” enabled when used with NSPersistentCloudKitContainer.
Initially, we tried storing image files manually on disk and only saving the metadata (file URLs, dimensions, etc.) in Core Data. While this approach reduced the size of the Core Data store, it introduced instability after app updates and broke sync between devices. We would prefer to use the official Apple-recommended method and have Core Data manage image storage and CloudKit syncing natively.
Specifically, we’d appreciate guidance on the following:
When a Binary Data attribute is marked as “Allows External Storage”, large image files are stored as separate files on device rather than inline in the SQLite store.
How effective is this mechanism in keeping the Core Data store size small on device?
Are there any recommended size thresholds or known limits for how many externally stored blobs can safely be managed this way?
How are these externally stored files handled during CloudKit sync?
Does each externally stored Binary Data attribute get mirrored to CloudKit as a CKAsset?
Does external storage reduce the sync payload size or network usage, or is the full binary data still uploaded/downloaded as part of the CKAsset?
Are there any bandwidth implications for users syncing via their private CloudKit database, versus developer costs in the public CloudKit database?
Is there any difference in CloudKit or Core Data behavior when a Binary Data attribute is managed this way versus manually storing image URLs and handling the file separately on disk?
Our goal is to store user-generated images efficiently and safely sync them via CloudKit, without incurring excessive local database bloat or CloudKit network overhead.
Any detailed guidance or internal performance considerations would be greatly appreciated.
Thank you,
Paul Barry
Founder & Lead Developer — Boat Buddy / Vessel Buddy iOS App
Archipelago Environmental Solutions Inc.