iCloud & Data

RSS for tag

Learn how to integrate your app with iCloud and data frameworks for effective data storage

CloudKit Documentation

Post

Replies

Boosts

Views

Activity

CoreData result class has 'Sendable' warnings
In an iOS viewController, I use the NSDiffableDataSource to populate a tableView from the results of a CoreData fetchController. The result class is defined by CoreData - in this case a class named CDFilterStack. In xCode 16.0 Beta with strict concurrency checking = 'Complete' the CDFilterStack class has this warning everywhere it is referenced. "Type 'CDFilterStack' does not conform to the 'Sendable' protocol; this is an error in the Swift 6 language mode." The class definition of CDFilterStack is not editable because it is generated by CoreData. I think I need to mark this class (and other similar classes) as @preconcurrency... but how & where? Here's one method sample that generates three of these warnings func initialSnapShot() -> NSDiffableDataSourceSnapshot<Int, CDFilterStack> { var snapshot = NSDiffableDataSourceSnapshot<Int, CDFilterStack>() if let sections = dataProvider.fetchedResultsController.sections { for index in 0..<sections.count { let thisSection = sections[index] guard let sectionStacks = thisSection.objects as? [CDFilterStack] else { continue} snapshot.appendSections([index]) snapshot.appendItems(sectionStacks) } // for loop that will continue on error in objects } return snapshot } Careful reading of the various migration guides hasn't produced an example of how to handle this.. (btw the migration guides are nicely done:)
1
0
75
1d
Library/Caches for app groups: automatically deleted when needed ?
In an app we can use FileManager.SearchPathDirectory.cachesDirectory (objc:NSCachesDirectory) to store files that could be recreated if necessary (and will be automatically deleted by iOS in cases of low disk memory). For app groups, there is a shared location that is automatically created as soon as we use containerURL(forSecurityApplicationGroupIdentifier:) (objc:containerURLForSecurityApplicationGroupIdentifier) : Library/Caches Is this cache directory (created by iOS) also gets automatically deleted by iOS in cases of low disk memory ? I also have more related questions : does this cache directory size count in the used disk space by the app displayed in the settings app ? is this cache directory (and same question for the top containerURL directory) saved in the cloud backups ? Does anyone have any information about this?
4
0
97
4d
`Task` at `createSampleData` function in What's new in SwiftData session
I was looking to the example code that point from What's new in SwiftData session and noticed something that I cannot understand about Swift concurrency. from this snippet: static func createSampleData(into modelContext: ModelContext) { Task { @MainActor in let sampleDataTrips: [Trip] = Trip.previewTrips let sampleDataLA: [LivingAccommodation] = LivingAccommodation.preview let sampleDataBLT: [BucketListItem] = BucketListItem.previewBLTs let sampleData: [any PersistentModel] = sampleDataTrips + sampleDataLA + sampleDataBLT sampleData.forEach { modelContext.insert($0) } if let firstTrip = sampleDataTrips.first, let firstLivingAccommodation = sampleDataLA.first, let firstBucketListItem = sampleDataBLT.first { firstTrip.livingAccommodation = firstLivingAccommodation firstTrip.bucketList.append(firstBucketListItem) } if let lastTrip = sampleDataTrips.last, let lastBucketListItem = sampleDataBLT.last { lastTrip.bucketList.append(lastBucketListItem) } try? modelContext.save() } } From the code snippet, I cannot see any task that needs to be marked with await, and it is also marked as @MainActor. My question is: why do we need to put Task here? It seems like all the code will run on the main thread anyway. I am just afraid that I might be missing some concept of Swift concurrency or SwiftData here. Thank you
2
0
145
2d
I'm using CloudKit+CoreData to sync ... looking for faster alternative channel when multiple computers are editing at same time
I am using CloudKit+CoreData to store and sync and share my apps data. In my somewhat limited testing this is working quite well, but sync performance is unpredictable. Often it is very fast, sometimes it just stops until I put Mac app in background or restart. I guess from this thread this behavior is by design: https://developer.apple.com/forums/thread/756315 I'm accepting that! :) My plan is that I will use CloudKit+CoreData for source of truth syncing, but now I'm looking for an alternative channel that I can use to sync when multiple devices are working on this data at the same time. I think the basic design could be: When a device starts editing a CKRecord Post device IP and record ID to well known location/discovery service Watch that location to see other devices that are editing that record Make direct connection to those devices and sync through that connection (still also saving/merging with iCloud). I think I know how to solve the data merge problems that will show up in this scenario, but I don't know what technologies I should use to create the sync channel. I'm looking for ideas. I don't want to run my own server. SharePlay session seems almost perfect, but I'm not sure if it's really intended for this purpose. In particular I would want the session to start automatically (using participants from CKShare) without users having to manually join. Also I would like it to work with a single account (when I am viewing same data on my Mac and iOS device). My other thought is that I would store active users+ip's in the synced CloudKit+CoreData store and then use Network.framework to connect and sync those active users. I think this could work, but is quite low level and might be a lot of work. Are there other options that I'm missing or things I should think about? Thanks, Jesse
0
0
54
1d
Prevent Data Retention in Core Data When View is Dismissed
Prerequisite Information I am trying to use Core Data in my SwiftUI app. I have created 3 entities, a Record, a Header and an Entry. The Record contains the Header entities. The Header contain other Header or Entry entities. The Entry has a title and a value. My List view looks like this, I fetch the records with a @FetchRequest. NavigationView { List { ForEach(records) { record in NavigationLink(destination: DetailView(headers: record.headers!.allObjects as? [Header] ?? [], isNewEntry: true)) { Text(record.id!.uuidString) } } } } In my DetailView I have a form that passes the details to other views which create a DisclosureGroup for a Header, a bold Text for a subheader, and a TextField for an Entry let headers: [Header] let isNewEntry: Bool @Environment(\.managedObjectContext) var managedObjectContext init(headers: [Header], isNewEntry: Bool = false) { self.headers = headers self.isNewEntry = isNewEntry } Form { ForEach(Array(headers.enumerated()), id: \.element) { index, header in HeaderView(header: header, isExpanded: Binding( get: { self.expandedStates[header.id!, default: false] }, set: { self.expandedStates[header.id!] = $0 } )) } } Problem When I press the record in the list, it takes me to the DetailView where I can write something in the TextField. Then if I slide back and do not press the save button and then press the same record again from the list, it retains the data I wrote in the TextField. Question How can I make it so that the data is not retained if I slide back except only when I press the save button? Please let me know if any other information is needed or if something is unclear.
0
1
89
2d
How can a user change some data in the public data base?
I am using the public cloud database to store my application data, this data is accessed by all users of the application, but at some point it is necessary for a user who did not create a respective data in the database to delete it, but from what I read in the documentation this is not possible, only with a permission. How do I allow a user to change or delete any data created by another user in the public cloud database?
1
0
311
Mar ’24
Restart sync when using NSPersistentCloudKitContainer
It's 2024, and it still seems like the only sure way to cleanly restart cloud sync on an app using NSPersistentCloudKitContainer is to uninstall and reinstall the app. No need to describe how bad that solution is... Am I missing something? Is there a better way to safely trigger such a restart of the sync (even if it means losing unsaved data and overwriting with what's in the cloud - which is what a reinstall does anyway)?
1
0
217
May ’24
Unable to login to iCloud on Simulator (to test SwiftData sync)
Xcode 15.2. Brand new simulator set up, running 17.2. Brand new AppleID, and have logged in and accepted terms. Totally unable to login to iCloud on the Simulator to test iCloud syncing. There are numerous threads dating back 6 years plus of people having issues logging in to iCloud on the Simulator. Seems like it's still an issue. I have tried every solution. Existing AppleID. New AppleID. Logged into iCloud on Safari on Desktop and Simulator to check for unaccepted terms. Still get the commonly reported Sign-in page sitting spinning endlessly. Checked Console for errors and only things that seem possibly related are: com.apple.shortcuts CloudKitSync info 13:41:04.506714+0000 siriactionsd -[VCCKShortcutSyncCoordinator updateAccountStatusAndUserRecordID]_block_invoke Not fetching current user record ID because iCloud account is not available Is it really still the case that logging in to iCloud on a Simulator, to test sign on or iCloud sync is still horribly broken, and has been for over 6 years?
2
1
410
Jan ’24
What is the proper way to handle videos in SwiftData ?
I'm creating an application with swiftui which gets images and videos from the Photos picker then store them with swiftData for later use. I save both images and videos as data with  @Attribute(.externalStorage). But it just seems wrong to me to store the videos that way, they can be several gigabytes in size . What is the correct way to handle something like this ? Is it to store the url and then each time the user wants to see a video save a temporary video ?. If that's the case can anyone show me how this should be done? Any comments appreciated Guillermo
0
0
64
3d
@Attribute(.unique) working as intended, kind of
I have a model that has a unique property, e.g.: @Model final class UserWord @Attribute(.unique) let word: String let partOfSpeech: PartOfSpeech let metaData: ... At the end of the init I have this: init(...) { if partOfSpeech == .verb { metaData = fetchMeta() } } This works fine when a word is newly created and saved. But let's say there's a unique conflict and a user tries to save a new entry with the same word. Apparently this init still fires and fetchMeta edits the existing entry which gives me the error: CoreData: error: Mutating a managed object 0xb890d8167c911ade <x-coredata://4C75194F-D923-477F-BB22-ACBDECCD7530/UserWord/p2> (0x600002170af0) after it has been removed from its context. I think the solution here is to do some manual checking of the modelContext before saving. Would love to hear other's thoughts.
0
0
79
4d
Swift Data Array with Elements to conform protocol
Hi, I'm try to convert from CoreData to SwiftData. Problem is that I'm using inheritance in CoreData. So, I have a base class "animal" and "cat" and "bird" inherit from it. I can have a array of type "animal" which contains both cats and dogs. Now as I try to move to SwiftData I tried the following approach protocol Animal { var name: String { get set } } @Model class Cat: Animal { var name: String var legs: Int } @Model class Bird: Animal { var name: String var legs: Int var wings: Int } @Model class Enviroment { //leads to error: //Type 'any Animal' cannot conform to 'PersistentModel' var animals: [any Animal] } So how to I get around of this? I would like to store multiple types of animals (classes that conform to protocol animal) … but how can I achieve that? Thanks
0
0
71
5d
'ID' is inaccessible due to '@_spi' protection level
When I reference the ID of a SwiftData model entity (aka PersistentIdentifier) anywhere as a type (like @State var selection: Set<SomeEntity.ID> = Set<SomeEntity.ID>()) I now get the following error: 'ID' is inaccessible due to '@_spi' protection level This never was a problem with CoreData and also not with SwiftData until the Xcode 15 RC. Does anybody know, if this is a bug or intended behaviour?
3
2
1k
Sep ’23
iOS 18 SwiftData ModelContext reset
Since the iOS 18 and Xcode 16, I've been getting some really strange SwiftData errors when passing @Model classes around. The error I'm seeing is the following: SwiftData/BackingData.swift:409: Fatal error: This model instance was destroyed by calling ModelContext.reset and is no longer usable. PersistentIdentifier(id: SwiftData.PersistentIdentifier.ID(url: x-coredata://34EE9059-A7B5-4484-96A0-D10786AC9FB0/TestApp/p2), implementation: SwiftData.PersistentIdentifierImplementation) The same issue also happens when I try to retrieve a model from the ModelContext using its PersistentIdentifier and try to do anything with it. I have no idea what could be causing this. I'm guessing this is just a bug in the iOS 18 Beta, since I couldn't find a single discussion about this on Google, I figured I'd mention it. if someone has a workaround or something, that would be much appreciated.
0
3
118
5d
Deleting CloudKit data
I have been testing an app which uses cloudKit with SWIFTDATA and after testing for several months my 200GB iCloud store is showing 168GB for iCloud Drive. Now my iCloud drive is only 22.6GB so the rest of the 168GB must be data from my app. Also, I have function in my app to delete all iCloud Data which I thought that should clean up iCloud storage but it does not. I tried resetting the Develop Environment but no change to iCloud data. Also I have several other containers in iCloud created while getting iCloud working which I would like to delete but I understand you can’t. https://forums.developer.apple.com/forums/thread/45251?answerId=788694022#788694022 Bottom line cloudkit console has been pretty much useless for me and I need a way to manage (delete containers and data). Am I missing something?
1
0
82
1w
Using Core Data with the Swift 6 language mode
I'm starting to work on updating my code for Swift 6. I have a number of pieces of code that look like this: private func updateModel() async throws { try await context.perform { [weak self] in // do some work } } After turning on strict concurrency checking, I get warnings on blocks like that saying "Sending 'self.context' risks causing data races; this is an error in the Swift 6 language mode." What's the best way for me to update this Core Data code to work with Swift 6?
3
1
286
1w
Please Create a Sendable Version of CKRecord or Make CKRecord Sendable
CKRecord is a class which does not conform to the Sendable protocol. Its fields consist of NSStrings, NSData and others which are not Sendable. I understand that Apple is incrementally modifying objects to be sendable, but I am experiencing and I would assume others are experiencing a very large number of warnings (for now) about CKRecords and Sendable. It may be too much to make CKRecord Sendable and it may be too much to create a Sendable version of CKRecord, but it would be nice if it could at least be investigated. My particular situation is I have created a Protocol named CKMethods which some of my view controllers use to download and upload CKRecords. I suddenly have a large number of warnings about non-sendable types being sent from main actor-isolated context to non-isolated instance method. The CKRecords sent to and from the protocol do not get mutated and I have never had a problem with data races in the years that I have had this protocol. At some point, the warnings will probably become errors and I definitely do not want to get to that point. I am still coming up to speed on Swift Concurrency, so there may be a more simple solution than the one I am working on - creating a Sendable Struct for every CKRecord type that I have in my app and modifying all of the methods to pass the Struct instead of a CKRecord and convert the Struct to a CKRecord for upload and convert the CKRecord to the Struct for download.
3
1
968
Apr ’23
Understanding Syncing between Core Data and CloudKit Public Database using NSPersistantCloudKitContainer
Can someone please give me an overview of how sync works between Core Data and the public CloudKit database when using the NSPersistentCloudKitContainer and please point out my misunderstandings based on what I describe below? In the following code, I'm successfully connecting to the public database in CloudKit using the NSPersistentCloudKitContainer. Below is how I have Core Data and CloudKit set up for your reference. In CloudKit I have a set of PublicIconImage that I created manually via the CloudKit Console. I intend to be able to download all images from the public database at the app launch to the local device and manage them via Core Data to minimize server requests, which works but only if the user is logged in. This is the behavior I see: When the app launches, all the CloudKit images get mirrored to Core Data and displayed on the screen but only if the user is logged in with the Apple ID, otherwise nothing gets mirrored. What I was expecting: I was under the impression that when connecting to the public database in CloudKit you didn't need to be logged in to read data. Now, if the user is logged in on the first launch, all data is successfully mirrored to Core Data, but then if the user logs off, all data previously mirrored gets removed from Core Data, and I was under the impression that since Core Data had the data already locally, it would keep the data already downloaded regardless if it can connect to CloudKit or not. What am I doing wrong? Core Data Model: Entity: PublicIconImage Attributes: id (UUID), imageName (String), image (Binary Data). CloudKit Schema in Public Database: Record: CD_PublicIconImage Fields: CD_id (String), CD_imageName (String), CD_image (Bytes). Core Data Manager class CoreDataManager: ObservableObject{ // Singleton static let instance = CoreDataManager() private let queue = DispatchQueue(label: "CoreDataManagerQueue") private var iCloudSync = true lazy var context: NSManagedObjectContext = { return container.viewContext }() lazy var container: NSPersistentContainer = { return setupContainer() }() func updateCloudKitContainer() { queue.sync { container = setupContainer() } } func setupContainer()->NSPersistentContainer{ let container = NSPersistentCloudKitContainer(name: "CoreDataContainer") guard let description = container.persistentStoreDescriptions.first else{ fatalError("###\(#function): Failed to retrieve a persistent store description.") } description.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey) let cloudKitContainerIdentifier = "iCloud.com.example.PublicDatabaseTest" let options = NSPersistentCloudKitContainerOptions(containerIdentifier: cloudKitContainerIdentifier) description.cloudKitContainerOptions = options description.cloudKitContainerOptions?.databaseScope = .public // Specify Public Database container.loadPersistentStores { (description, error) in if let error = error{ print("Error loading Core Data. \(error)") } } container.viewContext.automaticallyMergesChangesFromParent = true container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy return container } func save(){ do{ try context.save() }catch let error{ print("Error saving Core Data. \(error.localizedDescription)") } } } View Model Class class PublicIconImageViewModel: ObservableObject { let manager: CoreDataManager @Published var publicIcons: [PublicIconImage] = [] init(coreDataManager: CoreDataManager = .instance) { self.manager = coreDataManager loadPublicIcons() } func loadPublicIcons() { let request = NSFetchRequest<PublicIconImage>(entityName: "PublicIconImage") let sort = NSSortDescriptor(keyPath: \PublicIconImage.imageName, ascending: true) request.sortDescriptors = [sort] do { publicIcons = try manager.context.fetch(request) } catch let error { print("Error fetching PublicIconImages. \(error.localizedDescription)") } } } SwiftUI View struct ContentView: View { @EnvironmentObject private var publicIconViewModel: PublicIconImageViewModel var body: some View { VStack { List { ForEach(publicIconViewModel.publicIcons) { icon in HStack{ Text(icon.imageName ?? "unknown name") Spacer() if let iconImageData = icon.image, let uiImage = UIImage(data: iconImageData) { Image(uiImage: uiImage) .resizable() .aspectRatio(contentMode: .fit) .frame(width: 35, height: 35) } } } } .onAppear { // give some time to get the images downlaoded DispatchQueue.main.asyncAfter(deadline: .now() + 5){ publicIconViewModel.loadPublicIcons() } } } .padding() } }
0
0
80
1w