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

So in ios 17, I stored the login information in NSUserDefaults, and I opened the App again and the login information disappeared
In the system of iOS17, I store the login information through NSUserDefaults, but after the application is closed, I open it again, and the information stored in NSUserDefaults does not exist. I have not found the specific reason. I did not find this problem in the system before ios 17. This issue only appeared after iOS 17.
2
0
894
Feb ’24
SwiftData not working in VisionOS
I want to make icloud backup using SwiftData in VisionOS and I need to use SwiftData first but I get the following error even though I do the following steps I followed the steps below I created a Model import Foundation import SwiftData @Model class NoteModel { @Attribute(.unique) var id: UUID var date:Date var title:String var text:String init(id: UUID = UUID(), date: Date, title: String, text: String) { self.id = id self.date = date self.title = title self.text = text } } I added modelContainer WindowGroup(content: { NoteView() }) .modelContainer(for: [NoteModel.self]) And I'm making inserts to test import SwiftUI import SwiftData struct NoteView: View { @Environment(\.modelContext) private var context var body: some View { Button(action: { // new Note let note = NoteModel(date: Date(), title: "New Note", text: "") context.insert(note) }, label: { Image(systemName: "note.text.badge.plus") .font(.system(size: 24)) .frame(width: 30, height: 30) .padding(12) .background( RoundedRectangle(cornerRadius: 50) .foregroundStyle(.black.opacity(0.2)) ) }) .buttonStyle(.plain) .hoverEffectDisabled(true) } } #Preview { NoteView().modelContainer(for: [NoteModel.self]) }
0
0
516
Feb ’24
CloudKit Invalid bundle ID for container
I get this error even though everything is turned on, how can I solve it? It works on IOS but I get this error on VisionOS CoreData: error: CoreData+CloudKit: -[NSCloudKitMirroringDelegate _recoverFromPartialError:forStore:inMonitor:]_block_invoke(2726): <NSCloudKitMirroringDelegate: 0x600003b0c700>: Found unknown error as part of a partial failure: <CKError 0x600000cce460: "Permission Failure" (10/2007); server message = "Invalid bundle ID for container"; op = 7FE8CD52A7B2E8FC; uuid = D8D1F2C9-2C01-45B2-BECC-270CA5520D55; container ID = "iCloud.Multitools"> let previewContainer:ModelContainer = { do { let config = ModelConfiguration(cloudKitDatabase: .private("iCloud.Multitools")) let container = try ModelContainer(for: NoteModel.self, configurations: config) return container } catch { fatalError("Error to create container") } }()
1
0
662
Feb ’24
Core Data migration then run old app version
I'm sorta baffled right now. I am trying to wonder how I might detect a updated SQL Store in an older app. have a baseline app, and create a SQL-based repository in an updated app, change the model and verify that you can see the updated model version. Using lightweight migration re-run the older app (which will inherit the newer SQL repository). YIKES - no error when creating the NSPersistenStoreCoordinator! Nothing in the metadata to imply the store is newer than the model: [_persistentStoreCoordinator metadataForPersistentStore:store] My question: is there any way to detect this condition? David
0
0
397
Feb ’24
CKSyncEngine.RecordZoneChangeBatch and the CKSyncEngineDelegate protocol
I'm having some trouble with the following function from the CKSyncEngineDelegate protocol. func nextRecordZoneChangeBatch(_ context: CKSyncEngine.SendChangesContext, syncEngine: CKSyncEngine) async -> CKSyncEngine.RecordZoneChangeBatch? { The sample code from the documentation is func nextRecordZoneChangeBatch( _ context: CKSyncEngine.SendChangesContext, syncEngine: CKSyncEngine ) async -> CKSyncEngine.RecordZoneChangeBatch? { // Get the pending record changes and filter by the context's scope. let pendingChanges = syncEngine.state.pendingRecordZoneChanges .filter { context.options.zoneIDs.contains($0) } // Return a change batch that contains the corresponding materialized records. return await CKSyncEngine.RecordZoneChangeBatch( pendingChanges: pendingChanges) { self.recordFor(id: $0) } } init?(pendingChanges: [CKSyncEngine.PendingRecordZoneChange], recordProvider: (CKRecord.ID) -> (CKRecord?)) works fine for the sample app which only has one record type, but it seems incredible inefficient for my app which has a dozen different record types. The recordProvider gives you a CKRecord.ID, but not the CKRecord.RecordType. Searching each record type for a matching ID seems very inefficient. Doesn't the CKSyncEngine.PendingRecordZoneChange contain an array of CKRecords, not just CKRecord.IDs? According to the documentation CKSyncEngine.RecordZoneChangeBatch has a recordsToSave property, but Xcode reports 'CKSyncEngine.PendingRecordZoneChange' has no member 'recordsToSave' I'm looking for someway to get the CKRecords from syncEngine.state.pendingRecordZoneChanges.
3
1
549
Feb ’24
iOS App iCloud recovery
I implemented to my app iCloud backup and restore services. Basically App uploads it's document directory files to iCloud using NSURL containerURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil]; and [fileManager copyItemAtURL:fileURL toURL:destinationURL error:&error]; and everything has been OK to upload files. By checking my iCloud account, it has taken the space needed to store those files. However, when I changed my decice, I'm unable to get those files back. At first, files had .icloud extra extension added, but now the function just reports only 5 files from few hunder. The function used to get backup files is: `- (NSArray) getBackupFiles { NSError *error; NSURL *containerURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil]; if (!containerURL) return nil; // NSArray *keysArray = [[NSArray alloc] initWithObjects: nil]; NSArray *resultsArray = [[NSFileManager defaultManager] contentsOfDirectoryAtURL:containerURL includingPropertiesForKeys:nil options:NSDirectoryEnumerationSkipsHiddenFiles error:&error]; if (error) { [self myAlertView:error.localizedDescription]; return nil; } else return resultsArray; } Any ideas, what went wrong?`
0
0
362
Feb ’24
CloudKit: Not able to get the user's name through `CKContainer.default().shareParticipant(forUserRecordID: recordID)`
Hey everyone, I'm trying to get the user's name to display in a welcome screen, but unfortunatelly no success so far. For that, I'm using CKContainer.default().shareParticipant(forUserRecordID: recordID).userIdentity.nameComponents, but the returned nameComponents are empty, despite receiving no error and accountStatus of .available. Here's my code: struct Helper { static func getUserInformation() async throws -> Models.UserInfo { let container = CKContainer.default() let accountStatus = try! await container.accountStatus() var accountStatusDescription = "" switch accountStatus { case .couldNotDetermine: accountStatusDescription = "couldNotDetermine" case .available: accountStatusDescription = "available" case .restricted: accountStatusDescription = "restricted" case .noAccount: accountStatusDescription = "noAccount" case .temporarilyUnavailable: accountStatusDescription = "temporarilyUnavailable" @unknown default: accountStatusDescription = "default" } print("[Helper] CKContainer accountStatus: \(accountStatusDescription) ") // Prints "[Helper] CKContainer accountStatus: available" do { let recordID = try await container.userRecordID() let id = recordID.recordName let participant = try await container.shareParticipant(forUserRecordID: recordID) guard let nameComponents = participant.userIdentity.nameComponents else { throw Models.ServiceError.userIdentityUnknownName } print("[Helper] CKShare.Participant nameComponents \(nameComponents)") // Prints "[Helper] CKShare.Participant nameComponents - " print("[Helper] CKShare nameComponents.givenName \(String(describing: nameComponents.givenName))") print("[Helper] CKShare nameComponents.nickname \(String(describing: nameComponents.nickname))") print("[Helper] CKShare nameComponents.familyName \(String(describing: nameComponents.familyName))") print("[Helper] CKShare nameComponents.namePrefix \(String(describing: nameComponents.namePrefix))") print("[Helper] CKShare nameComponents.nameSuffix \(String(describing: nameComponents.nameSuffix))") print("[Helper] CKShare nameComponents.middleName \(String(describing: nameComponents.middleName))") let name = PersonNameComponentsFormatter().string(from: nameComponents) return Models.UserInfo( id: id, name: name ) } catch { throw error } } } Other than that, this project is using CloudKit for persistence through SwiftData and everything seems to be duly setup and working fine. Any idea of what I might be missing? Any user permissions required? As far as I understood, from iOS 17 on and using this code, no permissions are required anymore but I may be wrong. Any hint / help would be much appreciated! Cheers, Jorge
2
0
654
Feb ’24
SwiftData Migration Questions
I have couple of questions regarding app and schema version management related to SwiftData migration. For instance, it's common for the schema to change from V1 to V2 when updating an app from V1 to V2 and V3. This process seems reasonable to me. here's Moreover, if the versions go up to V10, does this mean I need to separate and organize stages for all migration codes, such as from V1 to V2, V2 to V3, up to V10, MigrationStages and Models for such exception handling? It was too wordy, here are my summary questions. 1. Can I limit to specific versions in my workspace?(e.g V1->2->3->1->2 .. so on) 2. if its not possible, For extensive versioning up to V10, should migration codes be organized for every incremental update for handling exceptions? 3. If I need to permanently record every stages and model, what improvements could be made to this structure?, can I get some useful tips?
0
0
416
Feb ’24
CoreData + CloudKit Notifications/Badging To Share Participants
What interfaces do I use to propagate a CloudKit change in a shared zone to a notification/badge to all participants in the shared zone? Assume I have a 'League' that is the root object in a shared zone and that N Players are members of the league. One of the players, the 'organizer', schedules a 'Game' that is open to any of the players. When the organizer creates the game (in the league's shared zone) and it is mirrored in CloudKit, how can the other players see it (as a timely notification)? I already observe .NSPersistentStoreRemoteChange on NSPersistentStoreCoordinator and NSPersistentCloudKitContainer.eventChangedNotification on NSPersistentCloudKitContainer. Are these delivered in the background? Can/Should they generate a 'local/remote' notification for handling at the AppDelegate level? How? Do I need to use a CKDatabaseSubscription looking for CD_Game records directly? (I'd rather not; because then I'd have a potential race between the remote iCloud database(s) and the local CoreData)
1
0
619
Mar ’24
Cannot convert value of type to closure result type 'any StandardPredicateExpression<Bool>'
Hi, I have issue when I use swift data in development and I'm beginner. I have two basic classes. @Model class User{ @Attribute(.unique) var id: UUID; var account: String; var password: String; var name: String; var role: Role @Relationship(inverse: \Transaction.tranInitiator) var transcations = [Transaction]() init(account: String, password: String, name: String, role: Role) { self.id = UUID() self.account = account self.password = password self.name = name self.role = role } } // @Model class Transaction{ @Attribute(.unique) var tranId: UUID; var tranName: String; var tranCash: Float; var tranDate: Date; @Relationship var tranInitiator: User; // init block } } and when I am going to fetch items I use predictor like let predictor = #Predicate<Transaction>{ tran in tran.tranInitiator == user } fetchDescriptorTrans = FetchDescriptor(predicate: predictor) let transList = try? contextTransaction?.fetch(fetchDescriptorTrans) if(transList!.isEmpty){return []} else{ return transList! } compiler shows error Cannot convert value of type 'PredicateExpressions.Equal<PredicateExpressions.KeyPath<PredicateExpressions.Variable, User>, PredicateExpressions.Value>' to closure result type 'any StandardPredicateExpression' I don't know why
1
0
1.5k
Mar ’24
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
575
Mar ’24
SwiftData synced to iCloud with one-to-many relationship between 2 models results in a crash when each model contains a reference to the other
I’m having an issue when two of my SwiftData models have a one-to-many relationship and I have them synced via CloudKit. To be clear, I’ve met all of the requirements to make it iCloud friendly and sync to work. I followed this https://www.hackingwithswift.com/quick-start/swiftdata/how-to-sync-swiftdata-with-icloud, and can confirm I’ve done it correctly because initially I was seeing this crash on startup when I had not: Thread 1: Fatal error: Could not create ModelContainer: SwiftDataError(_error: SwiftData.SwiftDataError._Error.loadIssueModelContainer) This is to say, the problem may be iCloud related but it’s not due to a wrong model setup. Speaking of which, these are models: @Model class Film { var name: String = "" var releaseYear: Int = 0 var director: Director? = nil init(name: String, releaseYear: Int, director: Director) { self.name = name self.releaseYear = releaseYear self.director = director } } @Model class Director { var name: String = "" @Relationship(deleteRule: .cascade, inverse: \Film.director) var films: [Film]? = [] init(name: String, films: [Film]) { self.name = name self.films = films } } I’ve set the delete rule for the relationship between Film and Director to be cascading because you can’t have a film without a director (to be clear, even when set as nullify, it doesn’t make a difference) And this is the @main App definition: @main struct mvpApp: App { var sharedModelContainer: ModelContainer = { let schema = Schema([ Film.self, Director.self ]) let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false) do { return try ModelContainer(for: schema, configurations: [modelConfiguration]) } catch { fatalError("Could not create ModelContainer: \(error)") } }() var body: some Scene { WindowGroup { ContentView() } } And this is the dummy ContentView: struct ContentView: View { var body: some View { EmptyView() .onAppear { let newDirector = Director(name: "Martin Scorcese", films: []) let film = Film(name: "The Wolf of Wall Street", releaseYear: 2019, director: newDirector) newDirector.films!.append(film) } } } I create a Director with no films assigned. I then create a Film, and the append it to the Director’s [Film] collection. The last step however causes a crash consistently: There is a workaround that involves removing this line from the Film init(): self.director = director // comment this out so it’s not set in a Film’s init() When I do this, I can append the (Director-less) Film to the Director’s [Film] collection. Am I misunderstanding how these relationships should work in SwiftData/CloudKit? It doesn’t make any sense to me that when two models are paired together that only one of them has a reference to the relationship, and the other has no knowledge of the link. The above is a minimum reproducible example (and not my actual application). In my application, I basically compromised with the workaround that initially appears to be without consequence, but I have begun to notice crashes happening semi-regularly when deleting models that I suspect must be linked to setting the foundations incorrectly.
1
0
899
Mar ’24
SwiftData - Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'NSFetchRequest could not locate an NSEntityDescription for entity name 'Workout
This piece of code was working properly until I Introduced the Exercise Model. I have tried everything like using migration scheme, removing the app, cleaning build folder, trying on different devices and simulator. Nothing seems to work now. I can't get the app to launch. struct LogbookApp: App { @State private var sharedModelContainer: ModelContainer = { let schema = Schema([ Workout.self, Exercise.self ]) let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false) do { return try ModelContainer(for: schema, configurations: [modelConfiguration]) } catch(let error) { fatalError("Could not create ModelContainer: \(error)") } }() var body: some Scene { WindowGroup { MainCoordinator() .view() } .modelContainer(sharedModelContainer) } } The models look like this @Model final class Exercise { var name: String var workout: Workout? init(name: String, workout: Workout? = nil) { self.name = name self.workout = workout } } @Model final class Workout { @Attribute(.unique) var id = UUID() @Relationship(deleteRule: .cascade) var exercises: [Exercise]? var type: WorkoutType var date: Date var duration: Int var customDescription: String init(id: UUID = UUID(), type: WorkoutType, date: Date, duration: Int, customDescription: String = "", exercises: [Exercise]? = []) { self.id = id self.type = type self.date = date self.duration = duration self.customDescription = customDescription self.exercises = exercises } }
2
1
747
Mar ’24
Xcode Version 15.3 (15E5202a): SwiftData/DataUtilities.swift:1093: Fatal error: Unable to parse keypath for non-PersistentModel Type
I'm running into a crash on launch in Simulator with my visionOS that uses SwiftData in Xcode Version 15.3 (15E5202a). This is printing to the console: SwiftData/DataUtilities.swift:1093: Fatal error: Unable to parse keypath for non-PersistentModel Type, and then it's crashing on _swift_runtime_on_report. This worked fine in Xcode 15.2. I'll return to Xcode 15.2 for now and report an issue, but is there anyone that can translate what this even means so I can fix it? Thanks
0
0
541
Mar ’24
SwiftData Migration Plan does not run custom migration stage
Hi, I'm trying to make some changes to my SwiftData model and I want to add a new non-optional property to one of my model classes. My current model was not part of a VersionedSchema so I first encapsulated it into one public enum FeynnDataModelsSchemaV1: VersionedSchema { public static var versionIdentifier: Schema.Version = .init(1, 0, 0) public static var models: [any PersistentModel.Type] { [FeynnDataModelsSchemaV1.Workout.self, FeynnDataModelsSchemaV1.Activity.self, FeynnDataModelsSchemaV1.ActivityRecord.self, FeynnDataModelsSchemaV1.WorkoutSession.self] } } Then I run the app and everything works as expected. Secondly, I create the V2 and add the new property: public enum FeynnDataModelsSchemaV2: VersionedSchema { public static var versionIdentifier: Schema.Version = Schema.Version(2, 0, 0) public static var models: [any PersistentModel.Type] { [FeynnDataModelsSchemaV2.Workout.self, FeynnDataModelsSchemaV2.Activity.self, FeynnDataModelsSchemaV2.ActivityRecord.self, FeynnDataModelsSchemaV2.WorkoutSession.self] } } extension FeynnDataModelsSchemaV2 { @Model final public class Activity: Hashable { ... public var activityType: ActivityType = ActivityType.traditionalStrengthTraining ... } } Lastly, I create the schema migration plan and add it to my modelContainer: public enum FeynnDataModelsMigrationPlan: SchemaMigrationPlan { public static var schemas: [VersionedSchema.Type] = [ FeynnDataModelsSchemaV1.self, FeynnDataModelsSchemaV2.self ] public static var stages: [MigrationStage] = [migrateV1toV2] public static var migrateV1toV2 = MigrationStage.custom(fromVersion: FeynnDataModelsSchemaV1.self, toVersion: FeynnDataModelsSchemaV2.self, willMigrate: {moc in let activities = try? moc.fetch(FetchDescriptor<Activity>()) print("\(activities?.count ?? 919191991)") }, didMigrate: {moc in let activities = try? moc.fetch(FetchDescriptor<Activity>()) print("\(activities?.count ?? 88888888)") activities?.forEach { activity in activity.activityType = .traditionalStrengthTraining } try? moc.save() }) } if let container = try? ModelContainer( for: Workout.self, Activity.self, ActivityRecord.self, WorkoutSession.self, migrationPlan: FeynnDataModelsMigrationPlan.self, configurations: ModelConfiguration(cloudKitDatabase: .automatic)) { self.container = container } else { self.container = try ModelContainer( for: Workout.self, Activity.self, ActivityRecord.self, WorkoutSession.self, migrationPlan: FeynnDataModelsMigrationPlan.self, configurations: ModelConfiguration(cloudKitDatabase: .none)) } After running this, the application runs as expected, but as soon as I render a view that references Activity.activityType the app crashes trying to get the value for my existing activities given that it is nil, pointing out that the migration stage was not ran? None of the print statements in the didMigrate or willMigrate can be found within the logs either. I have tried several approaches creating more VersionedSchemas and I run into more issues such as Cannot use stuck migration with an unknown model version. I feel like the current way of handling schema versions of SwiftData is very confusing and opaque for the developer to know what is going on. I don't know if the underlying database is picking the un-versioned schema, the V1 or the V2. Is there anything I'm doing wrong? What can I do apart from making the new property optional and having a computed property that unwraps it giving it a default value when nil? Thank you!
3
0
769
Mar ’24