If use a SortDescriptor for a model and sort by some attribute from a relationship, in DEBUG mode it all works fine and sorts. However, in release mode, it is an instant crash.
SortDescriptor(.name, order: .reverse) ---- works
SortDescriptor(.assignedUser?.name, order: .reverse) ---- works in debug but crash in release.
What is the issue here, is it that SwiftData just incompetent to do this?
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
Is there a way to view the data saved when using swiftdata? Even after deleting all models, the storage space taken up by the app in Settings is too large.
Hi,
I did cloudkit synchronization using swiftdata.
However, synchronization does not occur automatically, and synchronization occurs intermittently only when the device is closed and opened.
For confirmation, after changing the data in Device 1 (saving), when the data is fetched from Device 2, there is no change.
I've heard that there's still an issue with swiftdata sync and Apple is currently troubleshooting it, is the phenomenon I'm experiencing in the current version normal?
SwiftData ModelContainer instances don't seem to have a value for setting the Data Protection class.
Is the best way to set that by setting the Data Protection in the app capabilities? Is that the only way?
I have a need for log data that would be "Complete unless open" and user data that would be "Complete", but how do I change one of the containers data protection class?
I'm trying to handle the serverRecordChanged return code you get in CKError when you have a conflict and your using the savePolicy of ifServerRecordUnchanged.
According to the CKError.Code.serverRecordChanged documentation, I should be receiving all three records that I need to do a 3-way merge. The problem is that the ancestorRecord (CKRecordChangedErrorAncestorRecordKey can also be used to look it up in the userInfo) doesn't actually contain a record. It only contains the record metadata.
Is there something I need to be doing to get the full ancestorRecord in the CKError?
If not is it possible to query iCloud for the ancestorRecord? Given that iCloud has the change history (as I understand it), then it is theoretically possible. I just don't know how to do it if it is possible.
Are 3-way merges even possible? The design of the serverRecordChanged looks like that is the intent, but I can't see how to do it with the data that CloudKit is providing.
I'm a first time developer for Swift, (getting on a bit!) but after programming in VB back in the late 90s I wanted to write an app for iPhone. I think I might have gone about it the wrong way, but I've got an app that works great on my iPhone or works great on my iPad. It saves the data persistently on device, but, no matter how much I try, what I read and even resorting to AI (ChatGPT & Gemini) I still can't get it to save the data on iCloud to synchronise between the two and work across the devices. I think it must be something pretty fundamental I'm doing (or more likely not doing) that is causing the issue.
I'm setting up my signing and capabilities as per the available instructions but I always get a fatal error. I think it might be something to do with making fields optional, but at this point I'm second guessing myself and feeling a complete failure. Any advice or pointers would be really gratefully appreciated. I like my app and would like eventually to get it on the App Store but at this point in time I feel it should be on the failed projects heap!
I've even tried a new Xcode project for iOS and asking it to use SwiftData and CloudKit - the default project should work - right? But it absolutely doesn't for me. Please send help!!
I am following Apple's instruction to sync SwiftData with CloudKit. While initiating the ModelContainer, right after removing the store from Core Data, the error occurs:
FAULT: NSInternalInconsistencyException: This NSPersistentStoreCoordinator has no persistent stores (unknown). It cannot perform a save operation.; (user info absent)
I've tried removing default.store and its related files/folders before creating the ModelContainer with FileManager but it does not resolve the issue. Isn't it supposed to create a new store when the ModelContainer is initialized? I don't understand why this error occurs. Error disappears when I comment out the #if DEBUG block.
Code:
import CoreData
import SwiftData
import SwiftUI
struct InitView: View {
@Binding var modelContainer: ModelContainer?
@Binding var isReady: Bool
@State private var loadingDots = ""
@State private var timer: Timer?
var body: some View {
VStack(spacing: 16) {
Text("Loading\(loadingDots)")
.font(.title2)
.foregroundColor(.gray)
}
.padding()
.onAppear {
startAnimation()
registerTransformers()
let config = ModelConfiguration()
let newContainer: ModelContainer
do {
#if DEBUG
// Use an autorelease pool to make sure Swift deallocates the persistent
// container before setting up the SwiftData stack.
try autoreleasepool {
let desc = NSPersistentStoreDescription(url: config.url)
let opts = NSPersistentCloudKitContainerOptions(containerIdentifier: "iCloud.my-container-identifier")
desc.cloudKitContainerOptions = opts
// Load the store synchronously so it completes before initializing the
// CloudKit schema.
desc.shouldAddStoreAsynchronously = false
if let mom = NSManagedObjectModel.makeManagedObjectModel(for: [Page.self]) {
let container = NSPersistentCloudKitContainer(name: "Pages", managedObjectModel: mom)
container.persistentStoreDescriptions = [desc]
container.loadPersistentStores { _, err in
if let err {
fatalError(err.localizedDescription)
}
}
// Initialize the CloudKit schema after the store finishes loading.
try container.initializeCloudKitSchema()
// Remove and unload the store from the persistent container.
if let store = container.persistentStoreCoordinator.persistentStores.first {
try container.persistentStoreCoordinator.remove(store)
}
}
// let fileManager = FileManager.default
// let sqliteURL = config.url
// let urls: [URL] = [
// sqliteURL,
// sqliteURL.deletingLastPathComponent().appendingPathComponent("default.store-shm"),
// sqliteURL.deletingLastPathComponent().appendingPathComponent("default.store-wal"),
// sqliteURL.deletingLastPathComponent().appendingPathComponent(".default_SUPPORT"),
// sqliteURL.deletingLastPathComponent().appendingPathComponent("default_ckAssets")
// ]
// for url in urls {
// try? fileManager.removeItem(at: url)
// }
}
#endif
newContainer = try ModelContainer(for: Page.self,
configurations: config) // ERROR!!!
} catch {
fatalError(error.localizedDescription)
}
modelContainer = newContainer
isReady = true
}
.onDisappear {
stopAnimation()
}
}
private func startAnimation() {
timer = Timer.scheduledTimer(
withTimeInterval: 0.5,
repeats: true
) { _ in
updateLoadingDots()
}
}
private func stopAnimation() {
timer?.invalidate()
timer = nil
}
private func updateLoadingDots() {
if loadingDots.count > 2 {
loadingDots = ""
} else {
loadingDots += "."
}
}
}
import CoreData
import SwiftData
import SwiftUI
@main
struct MyApp: App {
@State private var modelContainer: ModelContainer?
@State private var isReady: Bool = false
var body: some Scene {
WindowGroup {
if isReady, let modelContainer = modelContainer {
ContentView()
.modelContainer(modelContainer)
} else {
InitView(modelContainer: $modelContainer, isReady: $isReady)
}
}
}
}
I have an Apple app that uses SwiftData and icloud to sync the App's data across users' devices. Everything is working well. However, I am facing the following issue:
SwiftData does not support public sharing of the object graph with other users via iCloud. How can I overcome this limitation without stopping using SwiftData?
Thanks in advance!
I'm using NSPersistentCloudKitContainer to save, edit, and delete items, but it only works half of the time. When I delete an item and terminate the app and repoen, sometimes the item is still there and sometimes it isn't. The operations are simple enough:
moc.delete(thing)
try? moc.save()
Here is my DataController. I'm happy to provide more info as needed
class DataController: ObservableObject {
let container: NSPersistentCloudKitContainer
@Published var moc: NSManagedObjectContext
init() {
container = NSPersistentCloudKitContainer(name: "AppName")
container.loadPersistentStores { description, error in
if let error = error {
print("Core Data failed to load: \(error.localizedDescription)")
}
}
#if DEBUG
do {
try container.initializeCloudKitSchema(options: [])
} catch {
print("Error initializing CloudKit schema: \(error.localizedDescription)")
}
#endif
moc = container.viewContext
}
}
I've been trying to setup a successful migration, but it keeps failing with this error:
NSCloudKitMirroringDelegate are not reusable and should have a lifecycle tied to a given instance of NSPersistentStore.
I can't find any information about this online. I added breakpoints throughout the code in willMigrate, and it originally failed on this line:
try? context.save()
I removed that, and it still failed. After I reload the app, it doesn't run the migration again and the app loads successfully. I figured since it crashed, it would keep trying, but I guess not. Here's how my migration is setup.
enum MigrationV1ToV2: SchemaMigrationPlan {
static var schemas: [any VersionedSchema.Type] {
[SchemaV1.self, SchemaV2.self]
}
static var stages: [MigrationStage] {
[stage]
}
static let stage = MigrationStage.custom(
fromVersion: SchemaV1.self,
toVersion: SchemaV2.self,
willMigrate: { context in
// Get cycles
let cycles = try? context.fetch(FetchDescriptor<SchemaV1.Cycle>())
if let cycles {
for cycle in cycles {
// Create new recurring objects based on what's in the cycle
for income in cycle.income {
let recurring = SchemaV2.Recurring(name: income.name, frequency: income.frequency, kind: .income)
recurring.addAmount(.init(date: cycle.startDate, amount: income.amount))
context.insert(recurring)
}
for expense in cycle.expenses {
let recurring = SchemaV2.Recurring(name: expense.name, frequency: expense.frequency, kind: .expense)
recurring.addAmount(.init(date: cycle.startDate, amount: expense.amount))
context.insert(recurring)
}
for savings in cycle.savings {
let recurring = SchemaV2.Recurring(name: savings.name, frequency: savings.frequency, kind: .savings)
recurring.addAmount(.init(date: cycle.startDate, amount: savings.amount))
context.insert(recurring)
}
for investment in cycle.investments {
let recurring = SchemaV2.Recurring(name: investment.name, frequency: investment.frequency, kind: .investment)
recurring.addAmount(.init(date: cycle.startDate, amount: investment.amount))
context.insert(recurring)
}
}
//try? context.save()
} else {
print("The cycles were not able to be fetched.")
}
},
didMigrate: { context in
// Get new recurring objects
let newRecurring = try? context.fetch(FetchDescriptor<SchemaV2.Recurring>())
if let newRecurring {
for recurring in newRecurring {
// Get all recurring with the same name and kind
let sameName = newRecurring.filter({ $0.name == recurring.name && $0.kind == recurring.kind })
// Add amount history to recurring object, and then remove matching
for match in sameName {
recurring.amountHistory.append(contentsOf: match.amountHistory)
context.delete(match)
}
}
//try? context.save()
} else {
print("The new recurring objects could not be fetched.")
}
}
)
}
Here's is my modelContainer in the app file. There is a fatal error occurring here that's crashing the app.
var sharedModelContainer: ModelContainer = {
let schema = Schema(versionedSchema: SchemaV2.self)
let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)
do {
return try ModelContainer(
for: schema,
migrationPlan: MigrationV1ToV2.self,
configurations: [modelConfiguration]
)
} catch {
fatalError("Could not create ModelContainer: \(error)")
}
}()
Does anyone have any suggestions for this?
EDIT:
I found this error in the console that may be relevant.
BUG IN CLIENT OF CLOUDKIT: Registering a handler for a CKScheduler activity identifier that has already been registered (com.apple.coredata.cloudkit.activity.export.8F7A1261-4324-40B4-B041-886DF36FBF0A).
CloudKit setup failed because it couldn't register a handler for the export activity. There is another instance of this persistent store actively syncing with CloudKit in this process.
And here is the fatal error
Fatal error: Could not create ModelContainer: SwiftDataError(_error: SwiftData.SwiftDataError._Error.loadIssueModelContainer, _explanation: nil)
I have transitioned to CKSyncEngine for syncing data to iCloud, and it is working quite well. I have a question regarding best practices for modifying and saving a CKRecord which already exists in the private or shared database.
In my current app, most CKRecords will never be modified after saving to the database, so I do not persist a received record locally after updating my local data model. In the rare event that the local data for that record is modified, I manually fetch the associated server record from the database, modify it, and then use CKSyncEngine to save the modified record.
As an alternative method, I can create a new CKRecord locally with the corresponding recordID and the modified data, and then use CKSyncEngine to attempt to save that record to the database. Doing so generates an error in the delegate method handleSentRecordZoneChanges, where I receive the local record I tried to save back inevent.failedRecordSaves with a .serverRecordChanged error, along with the corresponding server CKRecord. I can then update that server record with the local data and re-save using CKSyncEngine. I have not yet seen any issues when doing it this way.
The advantage of the latter method is that CKSyncEngine handles the entire database operation, eliminating the manual fetch step. My question is: is this an acceptable practice, or could this result in other unforeseen issues?
I've noticed several crashes that look like they're caused by an index out of bound in internal methods of NSFetchedResultsController. This happens while changes are merged from the persistent store container into the view context. Here's an example of the last exception backtrace.
Exactly which internal methods that are called in - [NSFetchedResultsController(PrivateMethods) _core_managedObjectContextDidChange:] vary between crash reports but they all end up crashing from _NSArrayRaiseBoundException.
The Core Data stack consists of one persistent store, one persistent store coordinator that the view context is set up to automatically merge changes from, and data is saved to disk from background context.
persistentContainer.loadPersistentStores(...)
viewContext = persistentContainer.viewContext
viewContext.automaticallyMergesChangesFromParent = true
backgroundContext = persistentContainer.newBackgroundContext()
backgroundContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
backgroundClientContext = persistentContainer.newBackgroundContext()
backgroundClientContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
Does anyone have any ideas what could be causing this? Thankful for any ideas or advice on how to investigate further.
Here’s the situation:
• You’re downloading a huge list of data from iCloud.
• You’re saving it one by one (sequentially) into SwiftData.
• You don’t want the SwiftUI view to refresh until all the data is imported.
• After all the import is finished, SwiftUI should show the new data.
The Problem
If you insert into the same ModelContext that SwiftUI’s @Environment(.modelContext) is watching, each insert may cause SwiftUI to start reloading immediately.
That will make the UI feel slow, and glitchy, because SwiftUI will keep trying to re-render while you’re still importing.
How to achieve this in Swift Data ?
I'm working on a macOS app with a Safari web extension. I'm trying to share a SwiftData model between devices using CloudKit synchronization. I am able to get synchronization in the main app on the same device, CloudKit sync works correctly — changes appear in the CloudKit Dashboard under com.apple.coredata.cloudkit.zone.
However, in the Safari App Extension, data is saved locally and persists across launches, but never syncs to CloudKit.
I have followed the recommended practices for configuring the App Group and entitlements, but the issue persists.
Questions:
Is there an official limitation preventing Safari App Extensions from connecting to the CloudKit daemon (cloudd)?
If not, what entitlements or configuration changes are required for a Safari App Extension to successfully sync with CloudKit?
Is the xpc_error=159 from bootstrap_look_up() a known sandbox restriction for this extension type?
Any guidance from Apple engineers or others who have successfully used CloudKit from a Safari App Extension would be appreciated.
What I’ve confirmed:
The extension’s .entitlements includes:
com.apple.security.app-sandbox
com.apple.developer.icloud-services
CloudKit
com.apple.developer.icloud-container-identifiers
iCloud.dev.example.myapp
Same iCloud container ID for both app and extension
CloudKit container exists and is initialized in CloudKit Console
Running in :Sandbox environment during development
Database name in SwiftData matches container identifier (without the iCloud. prefix)
The extension’s codesign output shows correct entitlements
App Group is configured (although in this case, extension and app use separate stores intentionally)
Observed behavior in Console.app logs:
CloudKit sync engine initializes in the extension
XPC activities are registered for import/export:
_xpc_activity_register: com.apple.coredata.cloudkit.activity.export.
xpc_activity_set_criteria: ... import.
Then a bootstrap lookup fails:
failed to do a bootstrap look-up: xpc_error=[159: Unknown error: 159]
CloudKit daemon connection error:
CKErrorDomain Code=6 "Error connecting to CloudKit daemon"
NSCocoaErrorDomain Code=4099
There is no “Will attempt to upload transactions” or “Upload succeeded” logs are ever seen.
Symptoms
When the extension is run, I see logs like the following in Console.app:
[0x13e215820] failed to do a bootstrap look-up: xpc_error=[159: Unknown error: 159]
CoreData+CloudKit: -[PFCloudKitSetupAssistant _checkAccountStatus:]_block_invoke(342): Fetched account info for store : (null)
Error Domain=CKErrorDomain Code=6 "Error connecting to CloudKit daemon. This could happen for many reasons..."
The NSPersistentCloudKitContainer synchronization between core data and
iCloud was working fine with phone 15.1. Connected a new iPhone iOS 15.5, it gives error:
CoreData: debug: CoreData+CloudKit: -[NSCloudKitMirroringDelegate managedObjectContextSaved:](2504): <NSCloudKitMirroringDelegate: 0x28198c000>: Observed context save: <NSPersistentStoreCoordinator: 0x2809c9420> - <NSManagedObjectContext: 0x2819ad520>
2022-12-05 13:32:28.377000-0600 r2nr[340:6373] [error] error: CoreData+CloudKit: -[NSCloudKitMirroringDelegate _importFinishedWithResult:importer:](1245): <PFCloudKitImporter: 0x2837dd740>: Import failed with error:
Error Domain=NSCocoaErrorDomain Code=4864 "*** -[NSKeyedUnarchiver _initForReadingFromData:error:throwLegacyExceptions:]: incomprehensible archive (0x53, 0x6f, 0x6d, 0x65, 0x20, 0x65, 0x78, 0x61)" UserInfo={NSDebugDescription=*** -[NSKeyedUnarchiver _initForReadingFromData:error:throwLegacyExceptions:]: incomprehensible archive (0x53, 0x6f, 0x6d, 0x65, 0x20, 0x65, 0x78, 0x61)}
CoreData: error: CoreData+CloudKit: -[NSCloudKitMirroringDelegate _importFinishedWithResult:importer:](1245): <PFCloudKitImporter: 0x2837dd740>: Import failed with error:
Error Domain=NSCocoaErrorDomain Code=4864 "*** -[NSKeyedUnarchiver _initForReadingFromData:error:throwLegacyExceptions:]: incomprehensible archive (0x53, 0x6f, 0x6d, 0x65, 0x20, 0x65, 0x78, 0x61)" UserInfo={NSDebugDescription=*** -[NSKeyedUnarchiver _initForReadingFromData:error:throwLegacyExceptions:]: incomprehensible archive (0x53, 0x6f, 0x6d, 0x65, 0x20, 0x65, 0x78, 0x61)}
I go back and try with my old iPhone iOS 15.1, gives same error.
I am trying to add a custom JSON DataStore and DataStoreConfiguration for SwiftData. Apple kindly provided some sample code in the WWDC24 session, "Create a custom data store with SwiftData", and (once updated for API changes since WWDC) that works fine.
However, when I try to add a relationship between two classes, it fails. Has anyone successfully made a JSONDataStore with a relationship?
Here's my code; firstly the cleaned up code from the WWDC session:
import SwiftData
final class JSONStoreConfiguration: DataStoreConfiguration {
typealias Store = JSONStore
var name: String
var schema: Schema?
var fileURL: URL
init(name: String, schema: Schema? = nil, fileURL: URL) {
self.name = name
self.schema = schema
self.fileURL = fileURL
}
static func == (lhs: JSONStoreConfiguration, rhs: JSONStoreConfiguration) -> Bool {
return lhs.name == rhs.name
}
func hash(into hasher: inout Hasher) {
hasher.combine(name)
}
}
final class JSONStore: DataStore {
typealias Configuration = JSONStoreConfiguration
typealias Snapshot = DefaultSnapshot
var configuration: JSONStoreConfiguration
var name: String
var schema: Schema
var identifier: String
init(_ configuration: JSONStoreConfiguration, migrationPlan: (any SchemaMigrationPlan.Type)?) throws {
self.configuration = configuration
self.name = configuration.name
self.schema = configuration.schema!
self.identifier = configuration.fileURL.lastPathComponent
}
func save(_ request: DataStoreSaveChangesRequest<DefaultSnapshot>) throws -> DataStoreSaveChangesResult<DefaultSnapshot> {
var remappedIdentifiers = [PersistentIdentifier: PersistentIdentifier]()
var serializedData = try read()
for snapshot in request.inserted {
let permanentIdentifier = try PersistentIdentifier.identifier(for: identifier,
entityName: snapshot.persistentIdentifier.entityName,
primaryKey: UUID())
let permanentSnapshot = snapshot.copy(persistentIdentifier: permanentIdentifier)
serializedData[permanentIdentifier] = permanentSnapshot
remappedIdentifiers[snapshot.persistentIdentifier] = permanentIdentifier
}
for snapshot in request.updated {
serializedData[snapshot.persistentIdentifier] = snapshot
}
for snapshot in request.deleted {
serializedData[snapshot.persistentIdentifier] = nil
}
try write(serializedData)
return DataStoreSaveChangesResult<DefaultSnapshot>(for: self.identifier, remappedIdentifiers: remappedIdentifiers)
}
func fetch<T>(_ request: DataStoreFetchRequest<T>) throws -> DataStoreFetchResult<T, DefaultSnapshot> where T : PersistentModel {
if request.descriptor.predicate != nil {
throw DataStoreError.preferInMemoryFilter
} else if request.descriptor.sortBy.count > 0 {
throw DataStoreError.preferInMemorySort
}
let objs = try read()
let snapshots = objs.values.map({ $0 })
return DataStoreFetchResult(descriptor: request.descriptor, fetchedSnapshots: snapshots, relatedSnapshots: objs)
}
func read() throws -> [PersistentIdentifier : DefaultSnapshot] {
if FileManager.default.fileExists(atPath: configuration.fileURL.path(percentEncoded: false)) {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
let data = try decoder.decode([DefaultSnapshot].self, from: try Data(contentsOf: configuration.fileURL))
var result = [PersistentIdentifier: DefaultSnapshot]()
data.forEach { s in
result[s.persistentIdentifier] = s
}
return result
} else {
return [:]
}
}
func write(_ data: [PersistentIdentifier : DefaultSnapshot]) throws {
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601
encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
let jsonData = try encoder.encode(data.values.map({ $0 }))
try jsonData.write(to: configuration.fileURL)
}
}
The data model classes:
import SwiftData
@Model
class Settings {
private(set) var version = 1
@Relationship(deleteRule: .cascade) var hack: Hack? = Hack()
init() {
}
}
@Model
class Hack {
var foo = "Foo"
var bar = 42
init() {
}
}
Container:
lazy var mainContainer: ModelContainer = {
do {
let url = // URL to file
let configuration = JSONStoreConfiguration(name: "Settings", schema: Schema([Settings.self, Hack.self]), fileURL: url)
return try ModelContainer(for: Settings.self, Hack.self, configurations: configuration)
}
catch {
fatalError("Container error: \(error.localizedDescription)")
}
}()
Load function, that saves a new Settings JSON file if there isn't an existing one:
@MainActor func loadSettings() {
let mainContext = mainContainer.mainContext
let descriptor = FetchDescriptor<Settings>()
let settingsArray = try? mainContext.fetch(descriptor)
print("\(settingsArray?.count ?? 0) settings found")
if let settingsArray, let settings = settingsArray.last {
print("Loaded")
} else {
let settings = Settings()
mainContext.insert(settings)
do {
try mainContext.save()
} catch {
print("Error saving settings: \(error)")
}
}
}
The save operation creates a JSON file, which while it isn't a format I would choose, is acceptable, though I notice that the "hack" property (the relationship) doesn't have the correct identifier.
When I run the app again to load the data, I get an error (that there wasn't room to include in this post).
Even if I change Apple's code to not assign a new identifier, so the relationship property and its pointee have the same identifier, it still doesn't load.
Am I doing something obviously wrong, or are relationships not supported in custom data stores?
When a user first downloads my application they are prompted to sign into their apple account via a pop up.
I have not had this pop up previously, I believe the change occurred after iOS18.
I have functions that do a few things:
Retrieves userRecordID
Retrieves a userprofile(via userrecordid) from cloudkit.
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.
LSUB always returns all the subscribed folders. For example
lsub "" "test/*"
returns a list of all the folders and not just subscribed folders that are subfolders of test. I.e, it returns the same folder list as
lsub "" "*".
For more details please see https://bugzilla.mozilla.org/show_bug.cgi?id=1817707#c15
I have a simple model
@Model
final class Movie: Identifiable {
#Index\<Movie\>(\[.name\])
var id = UUID()
var name: String
var genre: String?
init(name: String, genre: String?) {
self.name = name
self.genre = genre
}
}
I turned on SQL debugging by including '-com.apple.CoreData.SQLDebug 3' argument on launch.
When I fetch the data using the following code, it selects 3 records initially, but then also selects each record individually even though I am not referencing any other attributes.
var fetchDescriptor = FetchDescriptor\<Movie\>()
fetchDescriptor.propertiesToFetch = \[.id, .name\]
fetchDescriptor.fetchLimit = 3
do {
print("SELECT START")
movies = try modelContext.fetch(fetchDescriptor)
print("SELECT END")
} catch {
print("Failed to load Movie model.")
}
I see it selecting the 3 rows initially, but then it selects each one separately. Why would it do this on the initial fetch? I was hoping to select the data that I want to display and let the system select the entire record only when I access a variable that I did not initially fetch.
CoreData: annotation: fetch using NSSQLiteStatement <0x600002158af0> on entity 'Movie' with sql text 'SELECT 1, t0.Z_PK, t0.ZID, t0.ZNAME FROM ZMOVIE t0 LIMIT 3' returned 3 rows with values: (
"<NSManagedObject: 0x600002158d70> (entity: Movie; id: 0xa583c7ed484691c1 <x-coredata://71E60F4C-1A40-4DB7-8CD1-CD76B4C11949/Movie/p1>; data: <fault>)",
"<NSManagedObject: 0x600002158d20> (entity: Movie; id: 0xa583c7ed482691c1 <x-coredata://71E60F4C-1A40-4DB7-8CD1-CD76B4C11949/Movie/p2>; data: <fault>)",
"<NSManagedObject: 0x600002158f00> (entity: Movie; id: 0xa583c7ed480691c1 <x-coredata://71E60F4C-1A40-4DB7-8CD1-CD76B4C11949/Movie/p3>; data: <fault>)"
)
CoreData: annotation: fetch using NSSQLiteStatement <0x600002154d70> on entity 'Movie' with sql text 'SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZGENRE, t0.ZID, t0.ZNAME FROM ZMOVIE t0 WHERE t0.Z_PK = ? ' returned 1 rows
CoreData: annotation: with values: (
"<NSSQLRow: 0x600000c89500>{Movie 1-1-1 genre=\"Horror\" id=4C5CB4EB-95D7-4DC8-B839-D4F2D2E96ED0 name=\"A000036\" and to-manys=0x0}"
)
This all happens between the SELECT START and SELECT END print statements. Why is it fulfilling the faults immediately?