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

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
348
Jan ’24
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
248
Jan ’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
439
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
326
Jan ’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
277
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
561
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
655
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
367
Jan ’24
How to put app-specific logic between migration steps?
There was a section in the talk about how we can break down migration into smaller changes, and that we have an opportunity to run app-specific code in between migration steps. However the talk didn't touch on how can can achieve this, besides a single sentence, which doesn't give enough detail at least for me to figure out how to do it. Intuitively, an event loop could be built that opens the persistent store with the lightweight migration options set and iteratively steps through each unprocessed model in a serial order, and Core Data will migrate the store. Given the automatic nature of the lightweight migrations, especially in the case where we're using NSPersistentCoordinator, doesn't the automatic system just zoom through all of the migrations from model A --> A' --> A'' -> B? How to we make it stop so we can execute our own app code? Thanks!
2
2
1k
Jan ’24
Not receiving Persistent Store Remote Change Notification.
Before the code... CloudKit, background mode (remote notifications) and push notifications are added to Capabilities. Background sync is working fine and view loads current store on manual fetch. Code that initialises the persistent container in app delegate... - (NSPersistentCloudKitContainer *)persistentContainer {     // The persistent container for the application. This implementation creates and returns a container, having loaded the store for the application to it.     @synchronized (self) {         if (_persistentContainer == nil) {             _persistentContainer = [[NSPersistentCloudKitContainer alloc] initWithName:@"Expenses"];             [_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {                 if (error != nil) {                     __block NSPersistentStoreDescription *sDescription = storeDescription;                     dispatch_async(dispatch_get_main_queue(), ^(){                         [sDescription setOption:[NSNumber numberWithBool:YES] forKey:@"PersistentHistoryTracking"];                         [sDescription setOption:[NSNumber numberWithBool:YES] forKey:@"NSPersistentStoreRemoteChangeNotificationOptionKey"];                     }); #ifdef DEBUG                     NSLog(@"Unresolved error %@, %@", error, error.userInfo); #endif                     abort();                 }                 else #ifdef DEBUG                     NSLog(@"Store successfully initialized"); #endif             }];         }     }     return _persistentContainer; } In Home view controller which is the initial view controller i am adding an observer for the remote notification...     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadViewONCKChangeNotification) name:NSPersistentStoreRemoteChangeNotification object:[appDelegate.persistentContainer persistentStoreCoordinator]]; I am not receiving any store change notifications. Have added breakpoints to see if selector is fired. no go. CloudKit Console also doesn't show any pushes for the concerned time period.
4
0
1.2k
Jan ’24
WidgetKit using CoreData background context
Hi, In our tests, especially when we tested the new widgets with interactions (introduced in iOS 17), we found that sometimes they can hang when fetching data from CoreData using background context. I realise that there is no reason to use background context in widgets, but in our case we were reusing logic and so there were multiple background contexts. I'm trying to find information about using background context in widgets, but I can't find it. Now we avoid using background context in widgets, but it would be interesting to know if the use of CoreData background context in widgets is not allowed or could it be a kind of bug? Perhaps this information would be useful to anyone trying to find the cause of widget hangs.
0
0
332
Jan ’24
iOS extensions - order of installation
Hi, I have a few extensions for my iOS app: Share Extension, Widget extensions, Notification Extensions, Today Extension, WatchKit app. My app and all the extensions share data by loading the same Core Data sqlite database from a shared folder. One problem I'm having with this setup is with a Core Data lightweight migration. On updating the app to the new database model, I would like my main app to first make a backup of the database before the migration runs. But one of the app extensions always seems to run before the main app, and ends up performing the lightweight migration on the database file before the main app has a chance to backup the database sqlite file. I can just prevent the lightweight migration from happening when an app extension loads the persistent store (and only do lightweight migrations from the main app), but it might end up in a situation with incompatible formats for the extension, so I'm looking for a sturdier solution. When an app is installed (or an update to the app is installed), is there a way to check and control the order of the extensions that is installed / loaded by the system? That would help control the problem.
0
0
398
Jan ’24
Core Data modifications not saved in two of three tables
I'm a bit lost because of a problem I never experienced before, however, I have a suspicion. I use Core Data for data storage and DB Browser for SQLite for inspecting the database running in the Simulator. Here's the relevant function where all Core Data handling happens: /** Creates a new ComposedFoodItem from the ComposedFoodItemViewModel. Creates the related FoodItem and the Ingredients. Creates all relationships. - Parameter composedFoodItemVM: The source view model. - Returns: A Core Data ComposedFoodItem; nil if there are no Ingredients. */ static func create(from composedFoodItemVM: ComposedFoodItemViewModel, generateTypicalAmounts: Bool) -> ComposedFoodItem? { debugPrint(AppDelegate.persistentContainer.persistentStoreDescriptions) // The location of the .sqlite file let moc = AppDelegate.viewContext // Create new ComposedFoodItem (1) let cdComposedFoodItem = ComposedFoodItem(context: moc) // No existing composed food item, therefore create a new UUID cdComposedFoodItem.id = UUID() // Fill data cdComposedFoodItem.amount = Int64(composedFoodItemVM.amount) cdComposedFoodItem.numberOfPortions = Int16(composedFoodItemVM.numberOfPortions) // Create the related FoodItem (2) let cdFoodItem = FoodItem.create(from: composedFoodItemVM, generateTypicalAmounts: generateTypicalAmounts) // Relate both (3) cdComposedFoodItem.foodItem = cdFoodItem // Add cdComposedFoodItem to composedFoodItemVM composedFoodItemVM.cdComposedFoodItem = cdComposedFoodItem // Save before adding Ingredients, otherwise this could lead to an NSInvalidArgumentException (4) try? moc.save() // Add new ingredients (5) if let cdIngredients = Ingredient.create(from: composedFoodItemVM) { cdComposedFoodItem.addToIngredients(NSSet(array: cdIngredients)) // Save new composed food item try? moc.save() // Return the ComposedFoodItem return cdComposedFoodItem } else { // There are no ingredients, therefore we delete it again and return nil moc.delete(cdComposedFoodItem) try? moc.save() return nil } } What the function does: Creates a new entry in table ComposedFoodItem Creates another new entry in another table FoodItem Relates both entries Saves the modifications (and as of here I can see both new entries in the DB with all relations created correctly) Creates another 1..n entries in a third table Ingredient and links these to the entry created in step 1 All this works fine, I can see all relations and entries in the database. Then I quit and restart the app. The entry created in step 2 is still there, but the entries created in steps 1 and 5 are gone, as well as the relationships (of course). My suspicion: I recently implemented a Core Data migration from Data Model version 1 ("EasyFPU") to version 2 ("EasyFPU 2"). In this migration, I have two custom migration policies for exactly the two tables, which are not stored. The migration policies are pretty simple (and identical for both tables): /** No Ingredient is created in the destination model, i.e., there will be no Ingredients */ override func createDestinationInstances(forSource sourceIngredient: NSManagedObject, in mapping: NSEntityMapping, manager: NSMigrationManager) throws { // Do nothing on purpose debugPrint("Not migrating Ingredient with ID: \((sourceIngredient as? Ingredient)?.id.uuidString ?? "unknown")") } And what I suspect is, that this migration policies are somehow called when restarting the app, but I have no idea why, because the migration has already happened before. If I set a breakpoint in the debugPrint line of the code snippet above, I actually never reach this breakpoint - as expected. Nevertheless are the two tables Ingredient and ComposedFoodItem empty after restart. My AppDelegate Core Data persistentContainer variable looks like this: lazy var persistentContainer: NSPersistentCloudKitContainer = { let container = NSPersistentCloudKitContainer(name: "EasyFPU") container.loadPersistentStores(completionHandler: { (storeDescription, error) in if let error = error as NSError? { fatalError("Unresolved error \(error), \(error.userInfo)") } }) return container }() I tried to replace "EasyFPU" with "EasyFPU 2", but this apparently is not the version, but the container name. Any idea? Thanks in advance!
0
0
212
Jan ’24
Saving images to core data runs of memory
I'm trying to do a mass conversion of images to data so it can be stored in core data. The conversion part works fine, and if I do it without updating core data it shows memory usage at less that 100MB If I update the core data object, it just keeps consuming memory until the app crashes. func updateLocalImages() { let fetchRequest: NSFetchRequest<Picture> = Picture.fetchRequest() fetchRequest.predicate = NSPredicate(format: "pictureName != \"\"") do { let pictures = try moc.fetch(fetchRequest) print("Picture Update Count: \(pictures.count)") for picture in pictures { let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask) let path = paths[0] if let picName = picture.pictureName { let imagePath = path.appendingPathComponent(picName) if let uiImage = UIImage(contentsOfFile: imagePath.path) { if let imageData = uiImage.jpegData(compressionQuality: 1.0) { autoreleasepool { picture.pictureData = imageData print("Picture Updated") saveContext() } } } } } } catch { print("Fetching Failed") } } If I comment out the picture.pictureData = imageData line I don't get the memory issues. What's the correct way of going about this? There is an unknown number of images (mine current sits at about 5.5GB worth, 800+)
1
0
338
Jan ’24
GeometryReader cause FetchedResults object's view not updated after object's value changed.
Steps to reproduce: click any item in the list to get into its detail view click the + button to increase the count value of the item go back to the item list [ISSUE 1] the count value of the item is not updated in the list view now click the item you just operated to go back its detail view [ISSUE 2] the item's draft value is reverted back to the origin value (Or you can say it's the value displayed in the list view) If you remove the GeometryReader, it works normally, without that 2 issues. The Result I want: The list view's count value updated after going back to the list view. The draft value should be the same as the item at second entry after updating count. import SwiftUI import CoreData struct ContentView: View { @Environment(\.managedObjectContext) private var viewContext @FetchRequest( sortDescriptors: [NSSortDescriptor(keyPath: \Item.timestamp, ascending: true)], animation: .default) private var items: FetchedResults<Item> var body: some View { NavigationView { List { ForEach(items) { item in // Not Work GeometryReader { geo in NavigationLink(destination: SubView(item: item)) { HStack { Text("\(item.timestamp!.ISO8601Format())") Spacer(minLength: 0) Text(String(item.count)) } } } // Works // NavigationLink(destination: SubView(item: item)) { // HStack { // Text("\(item.timestamp!.ISO8601Format())") // Spacer(minLength: 0) // Text(String(item.count)) // } // } } } } } } struct SubView: View { @ObservedObject var item: Item @State private var draft: TmpItem init(item: Item) { self.item = item self._draft = State(wrappedValue: TmpItem(count: Int(item.count))) } var body: some View { VStack { Text("\(item.timestamp!.ISO8601Format())") Text("item: \(item.count)") Text("draft: \(draft.count)") Button("+") { draft.count += 1 item.count = Int16(draft.count) try! viewContext.save() } .buttonStyle(.borderedProminent) } } @Environment(\.managedObjectContext) private var viewContext } struct TmpItem { var count: Int } #Preview { ContentView().environment(\.managedObjectContext, PersistenceController.preview.container.viewContext) } It's base on the defualt demo code from Xcode 15.1.0 for iOS app with core data. Added a count field (Int16) to the Item object.
1
0
353
Dec ’23
Help with Widget Configuration
Hello, I'm working on my first app. It's also my first encounter with App Intents. I have a data structure for events that has an ID (String), a name (String), a Date and an image (Data). The user can create them in the app and they are stored with CoreData. I wanted to have a widget that would allow the user to choose from their list of events and display that event in the widget. The list should appear in the widget configuration and it would be a list of the names and (if possible) the image. I think I have found how to access the information from the widget, but I cannot figure out how to have the list appear in the configuration. I have been following this guide: https://developer.apple.com/documentation/widgetkit/making-a-configurable-widget?utm_source=pocket_saves. But that one shows hardcoded elements in the list and I haven't been able to find how to have the list change in relation to the content of the app. This is what I have made so far in the AppIntent file: import WidgetKit import AppIntents import CoreData struct EventDetail: AppEntity { static var defaultQuery: EventQuery = EventQuery() var id: String var date: Date var image: Data var title: String static var typeDisplayRepresentation: TypeDisplayRepresentation = "Event" var displayRepresentation: DisplayRepresentation { DisplayRepresentation(title: "\(id) \(title)") } } struct EventQuery: EntityQuery{ func entities(for identifiers: [EventDetail.ID]) async throws -> [EventDetail] { return fill_event_details(events_list: getEventDataIntent()) } func suggestedEntities() async throws -> [EventDetail] { fill_event_details(events_list: getEventDataIntent()).filter { $0.id != "-" } } func defaultResult() async -> EventDetail? { try? await suggestedEntities().first } } struct ConfigurationAppIntent: WidgetConfigurationIntent { static var title: LocalizedStringResource = "Select an event" static var description = IntentDescription("This is an example widget.") // An example configurable parameter. @Parameter(title: "Event") var event: EventDetail // init(events: [UserCountdowns]) { // self.event = fill_event_details(events_list: events)[0] // print("AppIntent") // print(self.event.title) // } init() { } } func fill_event_details(events_list: [UserCountdowns]) -> [EventDetail] { var entities_list: [EventDetail]? let events = getEventDataIntent() for event in events { entities_list!.append(EventDetail(id: event.id!, date: event.date!, image: event.image!, title: event.title!)) } return entities_list ?? [EventDetail(id: "-", date: Date(), image: Data(), title: "empty")] } func getEventDataIntent() -> [UserCountdowns] { let context = PersistenceController.shared.container.viewContext let request = UserCountdowns.fetchRequest() var result: [UserCountdowns]! do { result = try context.fetch(request) } catch { print(error) } return result } I have been trying a few things in the widget's code but I haven't been able to make anything work, so I don't really have anything worth sharing, I think. This is the code for the UserCountdowns structure: extension UserCountdowns { @nonobjc public class func fetchRequest() -> NSFetchRequest<UserCountdowns> { return NSFetchRequest<UserCountdowns>(entityName: "UserCountdowns") } @NSManaged public var date: Date? @NSManaged public var image: Data? @NSManaged public var title: String? @NSManaged public var id: String? } Could anyone help me with this, please? What am I missing or what would the next step be? Let me know if there is any other part of the code I should share. Thank you in advance!
0
0
536
Dec ’23
Cloudkit Error: "Invalid bundle ID for container"
I get the "Permission Failure" error ("Invalid bundle ID for container") below only when running my app from my iOS Target, and not my watchkit target. The watch app is able to sync/create/delete items, but my iOS target is unable to even read the data from the cloud. The cloudkit Container ID matches my iOS Target Bundle ID, which is the apps Bundle ID. Looking at the output of CKContainer, the container matches the iOS Bundle ID. I have tried reseting multiple times, creating different cloud containers, reseting the Signing and Capabilites online. It always results in the same issue... What am I missing here? <CKError 0x281b69590: "Partial Failure" (2/1011); "Failed to modify some record zones"; uuid = D57676F8-455E-4039-9DF4-824E3BAD42BE; container ID = "iCloud.companyName.AppName"; partial errors: { com.apple.coredata.cloudkit.zone:__defaultOwner__ = <CKError 0x281b771e0: "Permission Failure" (10/2007); server message = "Invalid bundle ID for container"; op = 8CCAD43B495AADC0; uuid = D57676F8-455E-4039-9DF4-824E3BAD42BE> }>
1
0
527
Dec ’23
Connect CoreData Container to SwiftData Container
I wrote an application using SwiftData to store data. But now I have rewritten it to CoraData because I would like to expand the list of available devices for downloading. All model classes have retained their names and all parameters too, but I don’t see data from the previous version. Is it possible to get into the same container? Maybe someone can tell me the name of the default container that is created by SwiftData.
0
0
302
Dec ’23