Core Data

RSS for tag

Save your application’s permanent data for offline use, cache temporary data, and add undo functionality to your app on a single device using Core Data.

Posts under Core Data tag

200 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

CoreData Transformable Types and SecureCoding
I have a CoreData entity with a transformable property data that stores an NSDictionary. All of the classes inside the dictionary conform to NSSecureCoding I have been getting many instances of this warning : 'NSKeyedUnarchiveFromData' should not be used to for un-archiving and will be removed in a future release In trying to clean up the warning and future-proof my app, but I am running into a lot of trouble. My understanding is that using NSKeyedUnarchiveFromData as the transformer in my data properties attribute should work, since the top level class is a dictionary and all of the contents conform to NSSecureCoding. However, my data dictionary is now coming back as NSConcreteMutableData so I cannot access the data in it. I have also tried creating a custom value transformer with additional allowedTopLevelClasses, but that hasn't helped, and again, the topLevel type is an NSDictionary, which should be allowed. Thank you for any guidance.
3
0
440
Feb ’24
App unresponsive when calling record(for:) on NSPersistentCloudKitContainer
I'm experiencing an unresponsive UI since MacOS 14.0 and iOS 17.0 when calling record(for: ) or recordID(for:) on the instance of NSPersistentCloudKitContainer. On MacOS, the UI freeze almost always happens when calling the function. On iOS, it is necessary that the device (or simulator) does not have any network connection. I would like to ask if anyone experienced the same problem. I have posted the problem twice to Apple via the Feedback app (once for iOS and once for MacOS). No reply yet on MacOS but on iOS Apple marked it as resolved because apparently no one but me has experienced this problem. In the meantime, I have set up a minimum reproducible example app (MRE).: https://github.com/DominikButz/NotesApp-Cloud-Kit-Record-UI-Freeze- Anyone interested, please read the readme of the repository. It includes step by step instructions on how to reproduce the bug. I can't rule out I have misunderstood the usage of CoreData and CloudKit - in that case please point me in the right direction. The app I'm working on should also work offline (and on MacOS!) but it doesn't do so properly as long as this bug exists. I'm exploring switching to SwiftData (which would mean no one using macOS 13 / iOS 16 can use my app...) but I would still need to access cloud kit records even with SwiftData and I fear the bug also exists in SwiftData. Thanks
3
0
313
Feb ’24
coredata entities from public configuration are not synchronized to cloudkit
In Core data public configuration, added new attribute to entities, new entities, but the changes are neither synchronized nor data is transferred to existing container schema in cloudkit. private var _publicPersistentStore: NSPersistentStore? var publicPersistentStore: NSPersistentStore { return _publicPersistentStore! } private var _privatePersistentStore: NSPersistentStore? var privatePersistentStore: NSPersistentStore { return _privatePersistentStore! } private var _sharedPersistentStore: NSPersistentStore? var sharedPersistentStore: NSPersistentStore { return _sharedPersistentStore! } static let shared = PersistenceController() static var preview: PersistenceController = { let result = PersistenceController(inMemory: true) let viewContext = result.container.viewContext do { try viewContext.save() } catch { // Replace this implementation with code to handle the error appropriately. // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. let nsError = error as NSError fatalError("Unresolved error \(nsError), \(nsError.userInfo)") } return result }() let container: NSPersistentCloudKitContainer init(inMemory: Bool = false) { container = NSPersistentCloudKitContainer(name: “GS”) if inMemory { container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null") } guard let defaultDescription = container.persistentStoreDescriptions.first else { fatalError("###\(#function): failed to retrieve a persistent store description.") } let containerIdentifier = defaultDescription.cloudKitContainerOptions!.containerIdentifier print(containerIdentifier) print(defaultDescription.url as Any) let url = defaultDescription.url?.deletingLastPathComponent() print(url as Any) // Public let publicDescription = NSPersistentStoreDescription(url: url!.appendingPathComponent("public.sqlite")) publicDescription.configuration = "Public" print(publicDescription.url) let publicOptions = NSPersistentCloudKitContainerOptions(containerIdentifier: containerIdentifier) publicOptions.databaseScope = .public publicDescription.cloudKitContainerOptions = publicOptions publicDescription.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey) publicDescription.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey) // Private let privateDescription = NSPersistentStoreDescription(url: url!.appendingPathComponent("private.sqlite")) privateDescription.configuration = "Private" print(privateDescription.url) let privateOptions = NSPersistentCloudKitContainerOptions(containerIdentifier: containerIdentifier) privateOptions.databaseScope = .private privateDescription.cloudKitContainerOptions = privateOptions privateDescription.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey) privateDescription.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey) // Shared guard let sharedDescription = privateDescription.copy() as? NSPersistentStoreDescription else { fatalError("#\(#function): Copying the private store description returned an unexpected value.") } sharedDescription.url = url!.appendingPathComponent("shared.sqlite") print(sharedDescription.url) sharedDescription.configuration = "Shared" let sharedOptions = NSPersistentCloudKitContainerOptions(containerIdentifier: containerIdentifier) sharedOptions.databaseScope = .shared sharedDescription.cloudKitContainerOptions = sharedOptions sharedDescription.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey) sharedDescription.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey) container.persistentStoreDescriptions = [publicDescription, privateDescription, sharedDescription] container.loadPersistentStores(completionHandler: { (storeDescription, error) in if let error = error as NSError? { // Replace this implementation with code to handle the error appropriately. // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. /* Typical reasons for an error here include: * The parent directory does not exist, cannot be created, or disallows writing. * The persistent store is not accessible, due to permissions or data protection when the device is locked. * The device is out of space. * The store could not be migrated to the current model version. Check the error message to determine what the actual problem was. */ fatalError("Unresolved error \(error), \(error.userInfo)") } else { if let cloudKitContainerOptions = storeDescription.cloudKitContainerOptions { if #available(iOS 16.0, *) { if .public == storeDescription.cloudKitContainerOptions?.databaseScope { print("loaded public store") // self._publicPersistentStore = container.persistentStoreCoordinator.persistentStore(for: storeDescription.url!) } else if .private == storeDescription.cloudKitContainerOptions?.databaseScope { print("loaded private store") //self._privatePersistentStore = container.persistentStoreCoordinator.persistentStore(for: storeDescription.url!) } else if .shared == storeDescription.cloudKitContainerOptions?.databaseScope { print("loaded shared store") //self._sharedPersistentStore = container.persistentStoreCoordinator.persistentStore(for: storeDescription.url!) } } else { // Fallback on earlier versions } } } }) container.viewContext.automaticallyMergesChangesFromParent = true container.viewContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy // external changes trumping in-memory changes. } func save() { let context = container.viewContext if context.hasChanges { do { try context.save() } catch { // Show some error here print("save error") } } } } Tried new container on cloudkit, problem persists. Working previously until I updated Xcode to 15.2 and iOs 16.2. Can you please tell me why coredata is not synchronized for public configuration.
2
0
317
Feb ’24
Core data heavy weight migration issues with big sized data
We are facing a challenging memory issue during a Core Data heavy weight migration in our app. Background: We store sizable data(~250kb/record) in a Core Data entity called "Email." We have roughly 20k records. We are loading the "Email" list using fetchedResultsController with batching. Recently, we split the another entity named "Profile" into "Profile" and "Address" entities, requiring a heavyweight migration. The Problem: This migration consumes an exorbitant amount of memory, causing the OS to kill our app. Interestingly, the "Email" entity is causing the brunt of the memory usage, even though the actual migration code deals with the "Profile" entity to create "Address." If we remove the "sizable" data from "Email" and attempt for migration then the migration is successful. My Questions: Is this memory consumption expected behavior? Why does the "Email" entity, seemingly unrelated to the actual migration, seem to be the main memory culprit? How can I prevent the OS from terminating my app during migration? Are there strategies to optimize memory usage or mitigate memory pressure? Also we are encountering a delay in loading the email list on the very first launch of app. Subsequent launches work comparatively faster. Is that related to storing bigger size data in Email entity?
1
1
305
Feb ’24
Core data issues with refactoring an entity
We have an entity called "EMail" with attributes such as ID, From, To, Subject, Body. Due to various reasons including performance for retrieval, impact on migration etc, we want to refactor this entity into two entities with a parent child relationship: "EMail": ID, From, To, Subject and "EMailBody": ID, Body. Can this be done with an existing model? If so, will this still fall under lightweight migration?
0
0
284
Feb ’24
CoreData/SwiftData persistent history error after adding additional models
I'm trying to add two more data models SectionsSD andArticles SD to an existing project using SwiftData where I had one model and am running into a variety of CoreData errors when I try to run my app. I am running Xcode 15.2 and the latest iOS simulator at iOS 17.2 Here is my container let container: ModelContainer = { let schema = Schema([ LocationData.self, SectionsSD.self, ArticlesSD.self ]) let container = try! ModelContainer(for: schema, configurations: []) return container }() After I add these two models I get the following errors and I can't load data into the SectionsSD and ArticlesSD models. If I comment out my LocataionData model that works w/o error or if I run just LocationData it runs without error but run all together and I get the following errors in the log: error: Error: Persistent History (11) has to be truncated due to the following entities being removed: ( SectionsSD, ArticlesSD ) CoreData: error: Error: Persistent History (11) has to be truncated due to the following entities being removed: ( SectionsSD, ArticlesSD ) warning: Warning: Dropping Indexes for Persistent History CoreData: warning: Warning: Dropping Indexes for Persistent History warning: Warning: Dropping Transactions prior to 11 for Persistent History CoreData: warning: Warning: Dropping Transactions prior to 11 for Persistent History warning: Warning: Dropping Changes prior to TransactionID 11 for Persistent History Any advice here would be appreciated. These are initial models so migration is not really a need yet. Seems to just **** if you add more models.
3
0
817
Mar ’24
SQlite FTS Queries Running Slow iOS 17.2.1 >=
As the title says, our app has begun running into a strange issue every time a user upgrades their iPhone to the latest iOS versions. It started in 17.2.1 and looks like it made a resurgence in 17.3. Post update the user's FullText Searches against the local sqlite db run egregiously slow. Fully re-installing the app and re-downloading all content seems to correct the issue, after which their searches come back in less than 500 ms tops. When the bug occurs searches can take upwards of 15 secs in some cases to complete... What makes no sense is why all of a sudden this is happening in 17.2.1 >= Our app uses an old school approach (historic code we never removed) to create a local sqlite database from scratch on first app install in the user's device contentDir. this .db file is instantiated on each app load using the following: private func sqliteOpenDB(url: URL) -> OpaquePointer? { var db: OpaquePointer? if sqlite3_open_v2(url.path, &db, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_FULLMUTEX, nil) == SQLITE_OK { LoggingUtil.log(msg: "\(ContentFilestore.TAG): database file opened successfully") // You must enable foreign key constraints every time the db connects otherwise they're off by default and cascade deletes/fk's won't work sqlite3_exec(db, "PRAGMA foreign_keys = ON;", nil, nil, nil) } else { LoggingUtil.log(msg: "\(ContentFilestore.TAG) Error: unabled to open the database file") } return db; } Prior to iOA 17.2.1 we've never had an issue with this when a user's device upgraded the OS. Now this process continues to work without throwing an error or warning of any kind, but their FTS search db slows to a crawl. It also seems to be completely isolated to the FTS virtual table as well. The actual tables run just fine. My question is did something major change in iOS 17.2.1 >= that I'm missing that would be causing virtual tables to lose their indexing or have some kind of issue that would cause this problem?
3
0
325
Jan ’24
Sharing CoreData objet with nested data
Is there a way to share CoreData data containing complex relationships easily by file? And also to create them easily after receiving the file? The application runs on a secure iPad without iCloud, so CloudKit is not an option. I'd really like to keep the file principle, so that data can be shared via Airdrop, e-mail, file transfer, etc. The ideal would be : data = myNSManagedObject.toJSON() file = createFile(data) share file receive file data = file.data.decodeJSON() myNSManagedObjectContext.add(data) All this without having to browse all the objects to create them individually Thx
0
0
200
Jan ’24
NSPersistentCloudkItContainer and iCloud synchronization speed issues
In our app, there is a scenario where we write and delete approximately 100MB of files to the iCloud server at once using NSPersistentCloudkItContainer(CoreData). While write, read, and delete operations are immediately reflected in the local database, there is a noticeable delay when accessing the CloudKit Database dashboard. Here is the testing approach we have tried: Data Insert Test
 Prepare around 100MB of data.
 Write the data to CoreData on device A.
 When launching the app on device B, it takes about 5 minutes for the data to be fully synchronized. Data Deletion Test Remove all the added data on device A (immediately reflected in local storage.)
 After performing step 1, leaving device A idle takes about 3 minutes for the deletion to be reflected on device B.
 if the app is deleted on device A after step 1, deletion information does not reach device B. Upon reinstalling the app on device A, the deleted data reappears on device B (synchronized data). The ongoing occurrence of these issues has raised several questions regarding cloud synchronization and synchronization speed: Is the synchronization speed of the Testflight app the same as the one received from the AppStore? Are there traffic limitations per account or device? Despite different perceived speeds for each account or device, is there any factor influencing synchronization speed other than network conditions?
2
0
337
Jan ’24
How to get notified on CKError.quotaExceeded
Hi all, I have an iOS app which uses CloudKit and the standard NSPersistentCloudKitContainer, which I rely on for syncing app data between the user's devices. If the user's iCloud account is full I can see a log message while debugging in Xcode shortly after startup which looks something like this: error: CoreData+CloudKit: -[NSCloudKitMirroringDelegate _requestAbortedNotInitialized:](2183): <NSCloudKitMirroringDelegate: 0x281ddc1e0> - Never successfully initialized and cannot execute request '<NSCloudKitMirroringExportRequest: 0x2841e00f0> 51383346-87BA-44D8-B527-A0B1EE35A0EF' due to error: <CKError 0x282c50db0: "Partial Failure" (2/1011); "Failed to modify some records"; uuid = 7BA17495-4F05-4AF4-A463-C0DF5A823B2E; container ID = "iCloud.com.neufsters.pangram"; partial errors: { E30B2972-FD4B-4D2A-BD1C-EB6F33F5367D:(com.apple.coredata.cloudkit.zone:__defaultOwner__) = <CKError 0x282c155f0: "Quota Exceeded" (25/2035); server message = "Quota exceeded"; op = FC4D3188D0A46ABC; uuid = 7BA17495-4F05-4AF4-A463-C0DF5A823B2E; Retry after 315.0 seconds> 2FC9A487-D630-444D-B7F4-27A0F3A6B46E:(com.apple.coredata.cloudkit.zone:__defaultOwner__) = <CKError 0x282c52820: "Quota Exceeded" (25/2035); server message = "Quota exceeded"; op = FC4D3188D0A46ABC; uuid = 7BA17495-4F05-4AF4-A463-C0DF5A823B2E; Retry after 315.0 seconds> 903DD6A0-0BD8-46C0-84FB-E89797514D9F:(com.apple.coredata.cloudkit.zone:__defaultOwner__) = <CKError 0x282c513e0: "Quota Exceeded" (25/2035); server message = "Quota exceeded"; op = FC4D3188D0A46ABC; uuid = 7BA17495-4F05-4AF4-A463-C0DF5A823B2E; Retry after 315.0 seconds> }> I would like to know how I can get a callback of some sort so I can run code if this CloudKit/CoreData error happens. In particular I'd like to put up some sort of warning to the user letting them know their data isn't going to sync. Please note that I'm not looking for how to do error handling as a result of a user-initiated CloudKit API call. I'm looking for how to get notified when the background syncing logs errors like the above. Thanks, Russ
3
0
366
1w
Core Data - Create a dynamic filter
I'm trying to setup a filter option for some core data records, but I'm not seeing the expected results. Essentially, what I want is to have multiple sections. Within each section it would be an OR query, and an AND between each section. I've tried setting it up as below. func getBasicFilter() -> NSPredicate? { var predicatesBagsLeft : [NSPredicate] = [] var predicatesDrillType : [NSPredicate] = [] var andPredicates : [NSPredicate] = [] print("Filter List") print(filters) // Bags Left if let show = filters["showFullLeft"] { if show { print("Predicates : Show Full") let predicate = NSPredicate(format: "ANY projectColours.fullLeft > 0") predicatesBagsLeft.append(predicate) } } if let show = filters["showPartialLeft"] { if show { print("Predicates : Show Partial") let predicate = NSPredicate(format: "ANY projectColours.partialLeft > 0") predicatesBagsLeft.append(predicate) } } // Drill Types if let show = filters["showSquareOnly"] { if show { print("Predicates : Show Square Only") let predicate = NSPredicate(format: "ANY projectColours.project.drillType = %@", "Square") predicatesDrillType.append(predicate) } } // Drill Manufacturers - TO DO // Combine Predicates if predicatesBagsLeft.count > 0 { let predicatesForBagsLeft = NSCompoundPredicate(type: .or, subpredicates: predicatesBagsLeft) andPredicates.append(predicatesForBagsLeft) } if predicatesDrillType.count > 0 { let predicatesForDrillType = NSCompoundPredicate(type: .or, subpredicates: predicatesDrillType) andPredicates.append(predicatesForDrillType) } if andPredicates.count > 0 { let predicates = NSCompoundPredicate(type: .and, subpredicates: andPredicates) return predicates } return nil } It does filter, but doesn't seem to be applying both correctly. I'm testing with a filter of showFullLeft & showSquareOnly, so it should show only squares which have a a fullest > 0 I'm getting 7 results back, but one of them is unwanted. It is square, but it has 0 for both full & partial When I look at the query core data is using it looks correct CoreData: sql: SELECT t0.ZMANU, COUNT (DISTINCT t0.Z_PK) FROM ZCOLOUR t0 JOIN ZPROJECTCOLOUR t1 ON t0.Z_PK = t1.ZCOLOUR JOIN ZPROJECTCOLOUR t2 ON t0.Z_PK = t2.ZCOLOUR JOIN ZPROJECT t3 ON t2.ZPROJECT = t3.Z_PK WHERE ( t1.ZFULLLEFT > ? AND t3.ZDRILLTYPE = ?) GROUP BY t0.ZMANU ORDER BY t0.ZMANU CoreData: details: SQLite bind[0] = 0 CoreData: details: SQLite bind[1] = "Square"
0
0
234
Jan ’24
SwiftData + CloudKit process for deduplication / consuming relevant store changes?
It is often the case that offline devices can add duplicate entities that needs to be merged when CloudKit syncs. Consider user-created tags. A user might create a Note, and then tag it with a newly created tag “Family.” On a separate offline device, they might create another note, and create another tag also called ”Family.” On device sync, both duplicate ”Family” tags would need to be identified as duplicates based on their name property, merged to a single entity, and their original relationships consolidated to the single merged Tag. And this needs to happen before the CloudKit sync data is presented to the UI in the main context. With Core Data we have the mechanism to consume relevant store changes described here. These tools allow us to listen for remote change, then process them appropriately (e.g. remove / merge duplicates) and then merge the changes into the app’s main context. This perfectly solves the problem described in the first paragraph above. Apple provides code using this mechanism for deduplicating tags in a sample app. Is there a mechanism to solve this deduplication problem using SwiftData technology without implementing and maintaining a parallel Core Data stack?
2
2
621
Feb ’24
CoreData+CloudKit w/ Large Public Database
What is the recommended architecture for a CoreData+CloudKit iOS App that has a large public database? Assume the public database contains 10,000+ Locations from which a User would select a few as favorites. Totally impractical to mirror the locations such that they appear in the App's CoreData having been synced from the .public CloudKit database. Presumably one uses the CloudKit API to query the .public database and display some subset of locations for the User to select? (The selected locations can then be stored in the Users .private (or perhaps .shared) database.) How does one configure CoreData + CloudKit for this scenario? Is there another approach?
2
0
417
Jan ’24
Convert Coredata PersistenceController to SwiftData container
Hello I have a CoreData PersistenceController and would like to convert it to a SwiftData container. Before converting the whole app to use SwiftData I wanted to know if my conversion is right and preserves old data (in iCloud and local). Here is the code: PersistenceController: import CoreData import SwiftUI import Combine #if os(iOS) || os(macOS) || os(watchOS) import WidgetKit #endif struct PersistenceController { static let shared = PersistenceController() let container: NSPersistentCloudKitContainer init() { let fileContainer = URL.storeURL(for: "group.Water-Alert-App", databaseName: "CoreData") container = NSPersistentCloudKitContainer(name: "CoreData") let defaultDirectoryURL = NSPersistentContainer.defaultDirectoryURL() let localStoreURL = defaultDirectoryURL.appendingPathComponent("Local.sqlite") let localStoreDescription = NSPersistentStoreDescription(url: localStoreURL) localStoreDescription.configuration = "Local" // Create a store description for a CloudKit-backed local store let cloudStoreDescription = NSPersistentStoreDescription(url: fileContainer) cloudStoreDescription.configuration = "Cloud" // Set the container options on the cloud store cloudStoreDescription.cloudKitContainerOptions = NSPersistentCloudKitContainerOptions(containerIdentifier: "iCloud.namel") cloudStoreDescription.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey) cloudStoreDescription.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey) container.persistentStoreDescriptions = [cloudStoreDescription, localStoreDescription] container.loadPersistentStores{ (storeDescription, error) in if let error = error as NSError? { fatalError("Unresolved error \(error), \(error.userInfo)") } } container.viewContext.automaticallyMergesChangesFromParent = true container.viewContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy } func save() { if container.viewContext.hasChanges { do { try container.viewContext.save() } catch { print("COULD NOT SAVE WITH CORE DATA") } } } } ModelContainer: var container: ModelContainer? = { let fileContainer = URL.storeURL(for: "group.Water-Alert-App", databaseName: "CoreData") let defaultDirectoryURL = NSPersistentContainer.defaultDirectoryURL() let localSchema = Schema([Reminder.self]) let cloudSchema = Schema([Goal.self, WaterData.self, Container.self]) let localConfiguration = ModelConfiguration("Local", schema: localSchema, url: defaultDirectoryURL.appendingPathComponent("Local.sqlite")) let cloudConfiguration = ModelConfiguration("Cloud", schema: cloudSchema, url: fileContainer, cloudKitDatabase: .private("iCloud.Water-Alert-App-Offical")) let container = try! ModelContainer(for: Reminder.self, Goal.self, WaterData.self, Container.self, configurations: localConfiguration, cloudConfiguration) return container }() Thank you!
0
1
299
Jan ’24
Core Data Migration
Hello, I’ve been struggling with Core Data lightweight migration since the iOS 17 launch. I have a NSPersistentStoreCoordinator which I use the following options in it: [NSMigratePersistentStoresAutomaticallyOption: true as AnyObject, NSInferMappingModelAutomaticallyOption: true as AnyObject, NSSQLitePragmasOption: ["journal_mode": "DELETE"] as AnyObject] I don’t create new versions when I change my .xcdatamodel. However, lightweight migration worked normally until iOS 17. And there is something else, the migration doesn’t fail for all users. So, if I update my xcdatamodel from version 1 to 2, some users get the following error: An error occurred during persistent store migration., reason: Failed to open the store, underlyingReason: The model used to open the store is incompatible with the one used to create the store Last but not least, my NSPersistentStoreCoordinator’s MOM merges two other models. But these two other models did not have any changes since I started getting this issue. I don’t think the issue is because we are adding new entities or properties in our xcdatamodel because if it were, it would be described in the error we are printing when trying to add the persistent store. I wonder if something has changed in iOS 17 that is causing this issue, which was working normally before. Also, what do you think I should do to fix this issue? Versioning my xcdatamodel? Although I don’t see it as a requirement in Apple’s docs. Removing the two other models from NSPersistentStoreCoordinator? Something else?
1
2
310
Feb ’24
What should happen if a Core Data app finds the Model is newer than its?
Have an app that has a half dozen models. We created a new app version with a new model that has an additional property on one entity. The options for the persistent store: do { let options = [ NSMigratePersistentStoresAutomaticallyOption: NSNumber(value: true), NSInferMappingModelAutomaticallyOption: NSNumber(value: true) ] let _ = try persistentStoreCoordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: storeURL, options: options) } catch { try? FileManager.default.removeItem(at: storeURL) //Erase old sqlite // Make new persistent store for future saves let _ = try? persistentStoreCoordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: storeURL, options: nil) } Launch this with data from a previous version. A breakpoint in the catch block never triggers so the migration must have worked. Since I'm in development, what happens if I run a different branch that doesn't have the new model? I assume the catch block is going to trigger—but it doesn't! Why doesn't it trigger? Does Core Data essentially ignore the new entity property, so all is well? I was just surprised ...
0
0
272
Jan ’24
CloudKit Sync Complete Event/Notification
How does one know when the CloudKit data in a CoreData+CloudKit (NSPersistentCloudKitContainer) has been fully synchronized. UseCase would be a user starts the App on a second device, user deletes then reinstalls the App, another User accepts a share and the share needs to sync. Is the containerEventChanged Notification for 'import success' the definitive event? CoreData: CloudKit: CoreData+CloudKit: -[NSCloudKitMirroringDelegate _finishedRequest:withResult:](3403): Finished request: <NSCloudKitMirroringImportRequest: 0x600002345d10> 729A742A-7F3B-42F1-B04C-72705D41FFEF with result: <NSCloudKitMirroringResult: 0x600000c4edc0> storeIdentifier: 79FA5848-A135-41B1-A36A-09F2F914D23D success: 1 madeChanges: 0 error: (null) As the sync could be time-consuming, is there a way to identify a single CloudKit record?
1
0
621
Jan ’24
Previews Crash on CoreData model using 'Parent Entity'
I have a CoreData model with two entities, 'User' and 'Player', that both use 'Person' as their 'Parent Entity'. While the App appears to work correctly in the simulator, including with CloudKit via NSPersistentCloudKitContainer, I get a crash in Xcode Previews: libswiftCore.dylib [ AGScoringModel/Persistence.swift:183: Fatal error: #init(inMemory:): Failed to load persistent stores:Error Domain=NSCocoaErrorDomain Code=134110 "An error occurred during persistent store migration." UserInfo={sourceURL=file:///Users/ebg/Library/Developer/.../CoreDataStores/private/database.sqlite, reason=Cannot migrate store in-place: Cannot merge multiple root entity source tables into one destination entity root table, destinationURL=file:///Users/ebg/Library/Developer/.../CoreDataStores/private/database.sqlite, NSUnderlyingError=0x600000ce02a0 {Error Domain=NSCocoaErrorDomain Code=134110 "An error occurred during persistent store migration." UserInfo={message=Cannot merge multiple root entity source tables into one destination entity root table, destinationRootEntity=Person, NSUnderlyingException=Cannot merge multiple root entity source tables into one destination entity root table, sourceRootEntities=( User, Player ), reason=Cannot merge multiple root entity source tables into one destination entity root table}}} ] Why is this? Something in my configuration for persistent container?
2
0
544
Jan ’24
'Establishing a User' - CloudKit Discoverability Deprecated.
My App uses Core Data + CloudKit and requires use of CloudKit to store persistent data, that will be shared between Users. I’d like to establish the User’s identity - like so they can augment their Core Data ‘Player’ entity w/ App specific info. Certain interfaces have been deprecated (‘user discoverability’). I’ve taken to creating a ‘dummy shared zone’ and extracting the ‘owner.userIdentity': public func establishUser () async -> User? { let container = cloudKitContainer // If we store the userUUID then the implication is that the `user` can // never be deleted; that is fair enough. let userUUIDKey = "userUUID" var userIdentity = Optional<CKUserIdentity>.none do { // // We'll store the UUID of the CoreData `User` in the CloudKit `User` record. If there // is no UUID in CloudKit, then this will be the first time the User has ever started // the App. We'll create a user and update the CloudKit `User` record // let userID = try await container.userRecordID () let userRecord = try await container.publicCloudDatabase.record (for: userID) // If the `userRecord` does not have a `userUUIDKey` then we must create a new `User`. if nil == userRecord[userUUIDKey] { // See if the user has the required iCloud account. let userStatus = try await container.accountStatus() guard userStatus == .available else { print ("JKP: \(#function) accountStatus: \(userStatus)") return nil } // // Create a `dummyShare` (in a 'dummyZone') so we can access the share's owner // That owner will have our `userIdentity` // do { let dummyZone = CKRecordZone (zoneName: UUID().uuidString) let dummyShare = CKShare (recordZoneID: dummyZone.zoneID) print ("JKP: User: Establish Zone: \(dummyZone.zoneID.zoneName)") // Save the dummyZone and then the dummyShare (for/in the dummyZone) let _ = try await container.privateCloudDatabase.save (dummyZone) let _ = try await container.privateCloudDatabase.save (dummyShare) // Extract the dummyShare's owner's identity - which is 'us/me' userIdentity = dummyShare.owner.userIdentity // Cleanup by deleting the 'dummyShare' and then the 'dummyZone' let _ = try await container.privateCloudDatabase.deleteRecord (withID: dummyShare.recordID) let _ = try await container.privateCloudDatabase.deleteRecordZone (withID: dummyZone.zoneID) } catch { print ("JKP: User Establish Error: \(error.localizedDescription)") } // Create `newUser` with the `userRecordId`. We'll use this to lookup the // Core Data User when players appear in a League. let newUser = User.create (context, scope: Player.Scope.owner, name: (userIdentity?.nameComponents ?? PersistenceController.nameDefault), identification: userIdentity?.lookupInfo .map { PlayerIdentification.create (lookupInfo: $0) } ?? PlayerIdentification()) … } Is this how getting the userIdentity is meant to be done (w/o using the deprecated interfaces)? The deprecated interfaces, when warned in Xcode, reference a sample project; that project doesn’t actually use/get the userIdentity. Also the deleteRecord and deleteRecordZone don’t appear to remove the dummy zone in CloudKit; why?
1
0
359
Jan ’24