I'm using NSPersistentCloudKitContainer with my app and everything has been working fine for the most part. However, every now and then I come across an entity that saves fine into core data but then can't sync to cloud kit and causes the entire cloud kit feature to stop working. The error happens when starting the app and looks like this:
error: CoreData+CloudKit: -NSCloudKitMirroringDelegate _requestAbortedNotInitialized:: <NSCloudKitMirroringDelegate: 0x2820187e0> - Never successfully initialized and cannot execute request '<NSCloudKitMirroringImportRequest: 0x283a27930> 3CD51F2A-E632-4FF0-8B8C-C17DCB15A002' due to error: <CKError 0x281739a10: "Partial Failure" (2/1011); "Failed to modify some records"; uuid = 9C4B94E0-662F-4B75-894B-55AD51DE9C79; container ID = "iCloud.com.mrsdizzie.LaurasBooks"; partial errors: {
0A2C0554-254E-47AA-B2C5-58F6C1CA038E:(com.apple.coredata.cloudkit.share.164680EE-7664-4105-9039-2FA952A013AB:__defaultOwner__) = <CKError 0x28173a6a0: "Invalid Arguments" (12/2006); server message = "Cannot create or modify field 'CD_data_ckAsset' in record 'CD_ImageData' in production schema"; op = 065A25FC65E7BB30; uuid = 9C4B94E0-662F-4B75-894B-55AD51DE9C79>
... 3 "Batch Request Failed" CKError's omited ...
}>
The app is for keeping track of Books, so the basic data model is an entity named Book with a relationship named imageData. This maps to an entity named ImageData with a field named data. data is of type "binary data" and where the cover image for a particular book is stored. This has worked so far for hundreds of entries into core data and cloud kit, but every now and then I see an error like this in the console app and the only way to recover is delete the offending entry (either manually, or by removing the app which deletes all local data). I am now able to reproduce it with one particular entry on one device in production, but not sure how to proceed from there.
Since all of this syncing and creation of CKRecords happens automatically via NSPersistentCloudKitContainer I'm not really sure what to do, how to recover, or how to get more details about what it doesn't like in this particular case. I've monitored NSPersistentCloudKitContainer.eventNotificationUserInfoKey for event errors but only get short errors like:
CKError Domain: 2, Description: The operation couldn't be completed
The production schema is up to date and hasn't changed. Most entries into the app work fine. It is only every so often with certain entries that this error happens. There is no obvious difference between entries that I can see. The image itself in this and other cases is under 1MB.
Any advice appreciated. Thanks!
CloudKit
RSS for tagStore structured app and user data in iCloud containers that can be shared by all users of your app using CloudKit.
Posts under CloudKit tag
200 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
Hello, I'm new to iOS development and I need help for working with CloudKit.
I have an application that allows me to add, delete and display information stored in a CloudKit container.
When I try to add a new record, this one can be visible into my CloudKit Console but if don't switch to a other view and back to my view (with my list of records) the record isn't displayed.
How can I update my list to reflect directly the new record add to my container ?
This is my code with split into different files (in attachment)
Sets : define my record struct
SetsView: list of my records
AddSetView: add new records
AddSetView-ViewModel : view model with my add function
SetsView-ViewModel: view model with my fetch function
Add function :
func add() async throws {
var newSet = set
newSet.name = name
newSet.code = code
newSet.releaseDate = releaseDate
newSet.numberOfCards = numberOfCards
let record = try await db.save(newSet.set)
guard let set = Set(record: record) else { return }
setsDictionary[set.id!] = set
print("Set added")
}
Fetch function :
func fetchSets() async throws {
let query = CKQuery(recordType: SetRecordKeys.type.rawValue, predicate: NSPredicate(value: true))
query.sortDescriptors = [NSSortDescriptor(key: "name", ascending: false)]
let result = try await db.records(matching: query) // récupère les données qui correspondent aux critères
let records = result.matchResults.compactMap { try? $0.1.get() } // Récupère les records
sets.removeAll()
records.forEach { record in
sets.append(Set(record: record)!)
}
print("Sets fetched")
print(sets)
}
Set.txt
SetsView.txt
AddSetView.txt
AddSetView-ViewModel.txt
SetsView-ViewModel.txt
I try to add some print to figure out what's going on, but I don't understand.
This is the console log for this scenario : open app without any data into the container > add a new record
First, the fetch function is executed but there is no data into the container (it's logic)
Second I add a new record (Set) :
Into the CloudKit console the new Set is visible
So for refresh my view with this record I need to re-call the fetch function. I tried many things but nothing works.
Even if the fetch function is called, the new record is not retrieved. Do you have any idea how to solve this problem?
Thanks for your help.
Trying to build an app that shares data across users, and one sanity check I was using was to check that the current user has granted permission to be looked up, and then I could display the user's name in the view. Previously, I could check the applicationPermissionStatus with CKContainer.applicationPermissionStatus(for:), and if it were not granted, I could request it with CKContainer.default().requestApplicationPermission. Both of those functions (and several others that i was using in my app) now pop up with the message: 'requestApplicationPermission' was deprecated in iOS 17.0: No longer supported. Please see Sharing CloudKit Data with Other iCloudUsers.
Unfortunately, I have found no alternate way to get the user identity in the Documentation, although it is a fairly large section and it's possible I am overlooking it. Is there a way to display the user's name components?
Hey,
I've been working with SwiftData for a while now and I'm currently in the process of adding iCloud functionality to my program. Everything works fine, but the data update only after running the app twice or restarting it twice in the simulator. It would be better if this could be done in real time or at the push of a button.
Does anyone have an idea how to implement this?
The devices send a message in the background (that there is an update) or? Can you access it somehow and the @Query update?
Imagine I have a game with new levels every day. Users play my game and their progress is saved in Core Data, which is then synchronized with CloudKit via NSPersistentCloudKitContainer.
Users' progress is about 500Kb for each level/day.
That's 5 Mb in 10 days. Or 182 Mb in a year.
If the user plays my game for a year, gets a new iPhone, and installs my app again — will the NSPersistentCloudKitContainer eventually download all 182 Mb of users' data!?
I am trying to make CloudKit Web service work by following the Apple Documentation at https://developer.apple.com/library/archive/documentation/DataManagement/Conceptual/CloudKitWebServicesReference/SettingUpWebServices.html
I am able to get the redirect URL from
curl --location 'https://api.apple-cloudkit.com/database/1/iCloud.Wasiq.Migraine/development/private/users/current?ckAPIToken=b440efde65bb8c1f45464598470f4cc73977f2c10d6c40587588ec9f1c1c56f0'
Now, with the redirect URL, if I login with Apple ID, I am expecting ckWebAuthToken
Documentations says If you did not specify a custom URL when creating the API token, register an event listener with the window object to be notified when the user signs in.
window.addEventListener('message', function(e) {
console.log(e.data.ckWebAuthToken);})
Here's a complete SwiftUI working project to reproduce the issue
import SwiftUI
import UIKit
import WebKit
struct ContentView: View {
@State private var loadWeb = false
@State private var url = ""
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundColor(.accentColor)
Text("Hello, world!")
.onTapGesture {
var request = URLRequest(url: URL(string: "https://api.apple-cloudkit.com/database/1/iCloud.Wasiq.Migraine/development/private/users/current?ckAPIToken=b440efde65bb8c1f45464598470f4cc73977f2c10d6c40587588ec9f1c1c56f0")!,timeoutInterval: Double.infinity)
request.httpMethod = "GET"
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data else {
print(String(describing: error))
return
}
do {
let res = try JSONDecoder().decode(Root.self, from: data)
print("Getting URL")
self.url = res.redirectURL
self.loadWeb = true
print(res.redirectURL)
} catch let error {
print(error)
}
}
task.resume()
}
if(!loadWeb){
Spacer()
}
else{
WebView(url: $url)
}
}
.padding()
}
}
struct Root: Codable {
let redirectURL: String}
struct WebView: UIViewRepresentable {
@Binding var url: String
func makeCoordinator() -> WebView.Coordinator {
Coordinator(self)
}
func makeUIView(context: Context) -> WKWebView {
let config = WKWebViewConfiguration()
let source = "window.addEventListener('message', function(e){ window.webkit.messageHandlers.logging.postMessage(e.data); })"
let script = WKUserScript(source: source, injectionTime: .atDocumentStart, forMainFrameOnly: false)
config.userContentController.addUserScript(script)
config.userContentController.add(context.coordinator, name: "logging")
let view = WKWebView(frame: UIScreen.main.bounds, configuration: config)
view.navigationDelegate = context.coordinator
view.load(URLRequest(url: URL(string: url)!))
return view
}
func updateUIView(_ uiView: WKWebView, context: Context) {
// you can access environment via context.environment here
// Note that this method will be called A LOT
}
class Coordinator: NSObject, WKNavigationDelegate, WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage)
{
print("message: \(message.body)")
// and whatever other actions you want to take
}
let parent: WebView
init(_ parent: WebView) {
self.parent = parent
}
}}
When I tap on "Hello, World", the WebView gets loaded and asks the user to Sign in with Apple ID. After logging in, I do not see the ckWebAuthToken getting printed
Instead I see the following output
message: SOAuthorizationDidStart
message: {
authorization = {
"grant_code" = "ce619474218c0485182af8cf019684d2e.0.sruq.i5r0nMCZIKVEBma6p6FE5Q";
"id_token" = "";
state = "auth-sznjvrn0-6svd-pw2c-lwfy-47rd7n64";
};
event = AppSSOTakeoverDidComplete;
user = {
};}
message: {
event = WidgetBridgeComplete;
state = "auth-sznjvrn0-6svd-pw2c-lwfy-47rd7n64";}
My App is in the App Store, and synced well between iOS devices with the same iCloud account. But after adding a new attribute to an entity 2 weeks ago, the CloudKit stopped syncing.
I checked the Cloudkit console, and can't find the new attribute there! I don't know Why. Actually this attribute already works well in the newest version of my App downloaded form App store.
Then I chose to deploy schema changes, but there are no changes to deploy!
So how to deploy the new change? and how to make the iCloud syncing work again?
Thanks!
In the application iCloud integration but in the container, it displays the name of the bundle that owns the container.
Configuration iCloud capability from developer account
Enable iCloud capability from Xcode
Added keys and value into info.plist file as below
<key>NSUbiquitousContainers</key>
<dict>
<key>iCloud.com.example.applepaydemo</key>
<dict>
<key>NSUbiquitousContainerName</key>
<string>Apple Demo</string>
<key>NSUbiquitousContainerIsDocumentScopePublic</key>
<true/>
<key>NSUbiquitousContainerSupportedFolderLevels</key>
<string>Any</string>
</dict>
</dict>
Issue: It displays applepaydemo name of container not Apple Demo in iCloud Manage Account Storage
Hi, developer
I have face the duplicate issue while using cloudkit. I am using registration app. I use cloudkit for generate UHID also. Is cloudkit is good to generate UHID.
My problem,
Cloudkit automatically sync the data in background at the time user create new reg.
Eg: Cloudkit had 20 data but in local it insert 11 data and is in progress at the user create new one, i fetch latest UHID and i get 11 at the time i get the duplicate. I use the deduplicate code also, but some times not helpful also if two user get reg data at the same time it get conflict.
Maybe I'm going about this completely the wrong way but I've got two stores loaded in my app: private and shared. I've got zone-wide sharing enabled and I can update records that exist in the shared database (on the participant device), and see updates sync when changed by the owner.
However, is it possible to save a new object specifically to the shared database as the participant? If I create a new object in my managed object context it saves it to the private database.
Can provide code if needed but it's more conceptual at this stage.
SwiftData CloudKit integration requires that all attributes be optional, or have a default value set
After install XCode 15 beta 6:
@Model
class WordResult {
var text = ""
var translation:[String] = []
init(){
}
}
got this error:
Variable 'self._$backingData' used before being initialized
so I changed to :
@Model
class WordResult {
var text:String
var translation:[String]
init(){
self.text = ""
self.translation = []
}
}
Then got this:
CloudKit integration requires that all attributes be optional, or have a default value set
It seems it can not work with cloudkit now.
coredata pushed schema to cloudkit only for those entities for which I created records. But the record data did not get pushed. I set recordName as Queryable and modifiedTimestamp as both Queryable and sortable. Query does not show the records. I look at Xcode console gives this output for one of the entities that got pushed to cloudkit :
CoreData: debug: CoreData+CloudKit: -[PFCloudKitSerializer newCKRecordsFromObject:fullyMaterializeRecords:includeRelationships:error:](575): Serializer has finished creating record: <CKRecord: 0x13f40f920; recordType=CD_Contact, recordID=26809600-B329-4C17-B3E1-6EA5FC177F7C:(com.apple.coredata.cloudkit.zone:__defaultOwner__), values={
"CD_contact" = "26809600-B329-4C17-B3E1-6EA5FC177F7C";
"CD_contactEmail_ckAsset",
"CD_contact",
"CD_contactEmail",
"<CKRecord: 0x13f40f920; recordType=CD_Contact, recordID=26809600-B329-4C17-B3E1-6EA5FC177F7C:(com.apple.coredata.cloudkit.zone:__defaultOwner__), recordChangeTag=5, values={\n \"CD_email\" = Email;\n \"CD_entityName\" = Contact;\n \"CD_firstName\" = V;\n \"CD_imageName\" = \"{ length=20834, sha256=d582bd2ccc7d93138b3a5ad4799443152860268e34f48ace54a0708f3e2f3aba }\";\n \"CD_lastName\" = R;\n \"CD_phone\" = 2;\n \"CD_screenName\" = Vr;\n \"CD_userRating\" = \"*****\";\n \"CD_userType\" = Household;\n}>",
Also schema for some other entities that do not have any core data records did not get pushed to CloudKit. I thought the entire coredata schema should get pushed along with the records. Looks like it is pushing those entities that have some records but without pushing data. I reset the cloudkit environment and tried again, but issue is not resolved.
Also the AppDelegate never gets called. I thought the line below should have called AppDelegate @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate: AppDelegate
Cross referenced persistenceController in AppDelegate. That did not help either
Code listed below. Please let me know how to fix the above two issues?
main
struct GreenApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate: AppDelegate
static var fcmToken: String?
let gcmMessageIDKey = "gcm.Message_ID"
let persistenceController = PersistenceController.shared
var body: some Scene {
WindowGroup {
ContentView()
.environment(\.managedObjectContext, persistenceController.container.viewContext)
}
}
}
struct PersistenceController {
static let shared = PersistenceController()
static var preview: PersistenceController = {
let result = PersistenceController(inMemory: true)
let viewContext = result.container.viewContext
// for _ in 0..<10 {
// let newItem = Item(context: viewContext)
// newItem.timestamp = Date()
// }
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: "Green")
if inMemory {
container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
}
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.
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
container.viewContext.automaticallyMergesChangesFromParent = true
container.viewContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy // external changes trumping in-memory changes.
}
}
Appdelegate code:
class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate, ObservableObject {
static var fcmToken: String?
let gcmMessageIDKey = "gcm.Message_ID"
let persistenceController = PersistenceController.shared
func applicationDidFinishLaunching(_ application: UIApplication) {
do {
// Use the container to initialize the development schema.
try persistenceController.container.initializeCloudKitSchema(options: [])
} catch {
// Handle any errors.
fatalError("###\(#function): failed to load persistent stores: \(error)")
}
if #available(iOS 10.0, *) {
// For iOS 10 display notification (sent via APNS)
UNUserNotificationCenter.current().delegate = self
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(options: authOptions, completionHandler: { granted, error in
})
} else {
let settings: UIUserNotificationSettings = UIUserNotificationSettings(types:[.alert, .badge, .sound], categories: nil)
application.registerUserNotificationSettings(settings)
}
DispatchQueue.main.async {
application.registerForRemoteNotifications()
}
}
}
I've got a simple Core Data Entity that is synchronized with CloudKit via NSPersistentCloudKitContainer. I can read my local fields, but how can I read fields like "Created" & "Modified" from CloudKit?
Do I have to add them to my Core Data model and populate them myself?
P.S. In his fantastic WWDC talk "Using Core Data with CloudKit", at around 21:40, Nick Gillet talks about how Core Data entities in the CloudKit store are prefixed with "CD_" to separate the things that it manages from the ones CloudKit implements. Then he says: "You wouldn't believe how many people add modify date to their CKRecord". Like it's something redundant.
Hello,
I want to use this observableobject that I made in SavingMovieView in MovieView
How do I do this...?
import SwiftUI
import CloudKit
struct MovieView: View {
@State var showingSavingMovieSheet:Bool = false
var body: some View {
NavigationView{
ZStack(alignment: .bottomTrailing){
//the list of movies
List{
//ForEach(vm.movies) { movies in
//}
//Your Name Block
NavigationLink {
//
} label: {
VStack{
Image("your name")
.resizable()
.aspectRatio(contentMode: .fill)
.cornerRadius(20)
Text("Your Name")
.fontWeight(.bold)
.font(.system(size:20))
}
.padding()
.background(Image("beige"))
}
//notting hill block
NavigationLink {
NottingHillView()
} label: {
VStack{
Image("notting hill")
.resizable()
.aspectRatio(contentMode: .fill)
.cornerRadius(20)
Text("Notting Hill")
.fontWeight(.bold)
.font(.system(size:20))
} .background(Image("beige"))
.padding()
}
//notting hill block
NavigationLink {
//Love_OtherDrugsView()
} label: {
VStack{
Image("love and other drugs")
.resizable()
.aspectRatio(contentMode: .fill)
.cornerRadius(20)
Text("Love & Other Drugs")
.fontWeight(.bold)
.font(.system(size:20))
}
.background(Image("beige"))
.padding()
}
}
.scrollContentBackground(.hidden)
.background(Image("beige"))
Button {
showingSavingMovieSheet.toggle()
} label: {
Image(systemName: "plus.circle.fill")
.font(.system(size: 70))
.foregroundColor(.accentColor)
.shadow(color: .gray, radius: 0.2, x: 1, y: 1)
}
.padding()
.sheet(isPresented: $showingSavingMovieSheet) {
SavingMovieView(vm: SavingMovieViewModel(container: CKContainer.default()))
.presentationDetents([.fraction(0.5)])
}
}
.edgesIgnoringSafeArea(.bottom)
.toolbar {
ToolbarItem(placement: .principal){
Text("Movies")
.font(Font.custom("Titan One",size:50))
.bold()
.foregroundColor(Color.accentColor)
}
}
}
}
}
struct MovieView_Previews: PreviewProvider {
static var previews: some View {
MovieView()
}
}
struct SavingMovieView: View {
//making an object from the viewModel
@StateObject private var vm: SavingMovieViewModel
@State private var title: String = ""
@State private var director: String = ""
@State private var stars: String = ""
@State private var review: String = ""
@Environment(\.dismiss) var dismiss
init(vm: SavingMovieViewModel){
_vm = StateObject(wrappedValue: vm)
}
var body: some View {
VStack{
Text("Add movie")
.bold()
.foregroundColor(Color.accentColor)
.font(Font.custom("Titan One",size:50))
TextField("Movie Title", text: $title)
.textFieldStyle(.roundedBorder)
TextField("Director Name", text: $director)
.textFieldStyle(.roundedBorder)
TextField("Number of rating stars", text: $stars)
.textFieldStyle(.roundedBorder)
TextField("Description", text: $review)
.textFieldStyle(.roundedBorder)
Button {
vm.saveMovie(title: title, director: director, stars: stars, review: review)
dismiss()
} label: {
Text("Save")
}
}
.padding()
}
}
struct SavingMovieView_Previews: PreviewProvider {
static var previews: some View {
SavingMovieView(vm: SavingMovieViewModel(container: CKContainer.default()))
}
}
Hello I've problem with transaction payload. If I receive POST App Store notification v2 to my server. In the decoded transaction body is missing appAccountToken field. In the iOS app I've just set token like this:
let result = try await product.purchase(options: [
.appAccountToken(UUID.encodeIntAsUUID(Auth.shared.user.idUser)),
.simulatesAskToBuyInSandbox(true)
])
Where is the problem?
Hello,
I recently started learning Swift and now I'm using Cloudkit to store user information.
I kinda have no idea what I'm doing but I watched this youtube tutorial to save user data and display it in UI instantly with DispatchQueue.main.async but it keeps throwing me an error, saying "No exact matches in call to instance method 'save'"
What I want to do is I want users to save a new record and I want this record to be updated instantly and be displayed on the screen.
How could I fix this?
import Foundation
import CloudKit
enum RecordType:String {
case movie = "Movie"
}
class SavingMovieViewModel : ObservableObject{
private var database :CKDatabase
private var container : CKContainer
@Published var movies: [SavingMovieModel] = []
init(container: CKContainer){
self.container = container
self.database = container.publicCloudDatabase
}
func saveMovie(title:String, director: String, stars:String, review: String){
let record = CKRecord(recordType: RecordType.movie.rawValue)
let movie = Movie(theTitle: title, theDirector: director, theStars: stars, theReview: review)
record.setValuesForKeys(movie.toDictionary())
// saving
self.database.save(record) { newRecord, error in. //<-- here is where the error is :(
if let error = error{
print(error)
}
else{
if let newRecord = newRecord{ //<-- this bit is the problem. i need the new record added to be displayed instantly
if let movie = Movie.fromRecord(newRecord){
DispatchQueue.main.async {
self.movies.append(SavingMovieModel(Movie: movie))
}
}
}
}
}
}
func whatMovies(){
//creating an array of movies
var movies: [Movie] = []
let query = CKQuery(recordType: RecordType.movie.rawValue, predicate: NSPredicate(value: true))
database.fetch(withQuery: query) { result in
switch result{
case.success(let result):
result.matchResults.compactMap{$0.1}
.forEach{
switch $0 {
case.success(let record):
if let movie = Movie.fromRecord(record){
movies.append(movie)
}
case.failure(let error):
print(error)
}
}
DispatchQueue.main.async {
self.movies = movies.map(SavingMovieModel.init)
}
case.failure(let error):
print(error)
}
}
}
}
struct SavingMovieModel{
let movie: Movie
var movieId :CKRecord.ID?{
movie.movieId
}
var title:String{
movie.title
}
var director:String{
movie.director
}
var stars:String{
movie.stars
}
var review:String{
movie.review
}
}
This is the Movie struct for Movie objects
import Foundation
import CloudKit
struct Movie{
var movieId: CKRecord.ID?
var title:String
var director:String
var stars:String
var review:String
init(movieId: CKRecord.ID? = nil, theTitle:String, theDirector:String, theStars:String, theReview:String){
self.title = theTitle
self.director = theDirector
self.stars = theStars
self.review = theReview
self.movieId = movieId
}
func toDictionary() -> [String:Any]{
return ["title": title, "director" :director, "stars":stars, "review": review]
}
static func fromRecord(_ record :CKRecord) -> Movie? {
guard let title = record.value(forKey:"title") as? String, let director = record.value(forKey:"director") as? String, let stars = record.value(forKey:"stars") as? String, let review = record.value(forKey:"review") as? String
else{
return nil
}
return Movie(movieId: record.recordID, theTitle: title, theDirector: director, theStars: stars, theReview: review)
}
}
Hi guys,
First of all, I'm sorry if this is the wrong place to post this. I'm in the last steps of my task manager app: getting the tasks to sync between devices. However, I get the error "This NSPersistentStoreCoordinator has no persistent stores (unknown). It cannot perform a save operation." What does this error exactly mean? My container is initialised so it should have a persistent store, right? I've also enabled all the proper capabilities I'm pretty sure (eg, I've enabled CloudKit, created a container, enabled background fetch and remote notifications.) Here is the code for my data controller:
import CoreData
import Foundation
class DataController: ObservableObject {
let container = NSPersistentCloudKitContainer(name: "TaskDataModel")
init() {
guard let description = container.persistentStoreDescriptions.first else {
fatalError("Container descriptions not loaded")
}
description.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
container.viewContext.automaticallyMergesChangesFromParent = true
container.loadPersistentStores { description, error in
if let error = error {
print("Core Data failed to load: \(error.localizedDescription)")
}
}
}
}
Here is TaskManMain:
@main
struct TaskManApp: App {
@StateObject private var dataController = DataController()
var body: some Scene {
WindowGroup {
MainView()
.environment(\.managedObjectContext, dataController.container.viewContext)
}
}
}
Here is the full repo if y'all are interested:
https://github.com/aabagdi/TaskMan
Thanks for any help!
I have narrowed my problem down to the many to many relationship between user and group record types. When a user transfers ownership of a group the new admin can change things like privacy (a field) but still only the original owner can leave or remove others. The new admin's use of remove user does nothing and no users can leave besides the creator. All security perms are enabled, and no permission not granted errors arise. I simply end up with two unsynced devices where one user observes themselves as having left, and the other that never will observe it. I can get around this a long way but don't really see why I should have to.
Anyone know the correct usage for CKQueryOperation.recordMatchedBlock and .queryResultBlock?
Xcode is telling me to use them as the old .recordFetchedBlock and .queryCompletionBlock are deprecated, but there isn't any documentation to say how they should be used. ChatGPT, Bard etc aren't able to provide a correct answer either:
specifically, I need to convert the following to use those methods:
operation.recordFetchedBlock = { record in
// Convert CKRecord to Core Data object and save to Core Data
self.saveToCoreData(record: record)
}
operation.queryCompletionBlock = { (cursor, error) in
// Handle potential errors
if let error = error {
print("Error syncing first of month records: \(error)")
}
if let cursor = cursor {
// There are more records to fetch for this category, continue fetching
self.continueSyncing(cursor: cursor, completion: completion)
} else {
// Done syncing this category, move to the next sync task
completion()
}
}
I've decided I want my app, which has been shipped to the App Store, to support CloudKit, but it's a .swiftpm app (so I could work on it on the go on an iPad and Swift Playgrounds).
I've taken a half-hearted stab at it (there's more pressing stuff to work on and this is a nice to have for the moment), but is there a way to set up a new workspace in Xcode where I have two targets: a .swiftpm version of the app and a .xcodeproj app so I can enable CloudKit for my app and also ship it to the App Store with the same identifier?