Good morning,
I've developed an application where we download a JSON of objects and we store those information on a CoreData table.
We've also created a Collection view used to show those information through a NSFetchedResultsController.
Can someone helps me to understand the reason why I get this issue?
Thanks indeed
Fatal Exception: NSInvalidArgumentException
0 CoreFoundation 0x83f20 __exceptionPreprocess
1 libobjc.A.dylib 0x16018 objc_exception_throw
2 CoreFoundation 0x1b6250 _NSArrayRaiseInsertNilException
3 CoreFoundation 0x16f5c -[__NSCFArray objectAtIndex:]
4 CoreData 0x13af14 -[_PFMutableProxyArray subarrayWithRange:]
5 CoreData 0xc4948 -[_NSDefaultSectionInfo objects]
6 CoreData 0x9c3fc -[NSFetchedResultsController _conditionallyDispatchSnapshotToDelegate:updatesInfo:]
7 CoreData 0x6d4ec __82-[NSFetchedResultsController(PrivateMethods) _core_managedObjectContextDidChange:]_block_invoke
8 CoreData 0x270dc developerSubmittedBlockToNSManagedObjectContextPerform
9 CoreData 0x9d0ec -[NSManagedObjectContext performBlockAndWait:]
10 CoreData 0x9c6e8 -[NSFetchedResultsController _core_managedObjectContextDidChange:]
11 CoreFoundation 0x5178c __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__
12 CoreFoundation 0x516a8 ___CFXRegistrationPost_block_invoke
13 CoreFoundation 0x515f0 _CFXRegistrationPost
14 CoreFoundation 0x4fbb8 _CFXNotificationPost
15 Foundation 0x31574 -[NSNotificationCenter postNotificationName:object:userInfo:]
16 CoreData 0x6a548 -[NSManagedObjectContext _createAndPostChangeNotification:deletions:updates:refreshes:deferrals:wasMerge:]
17 CoreData 0x69d10 -[NSManagedObjectContext _postRefreshedObjectsNotificationAndClearList]
18 CoreData 0x68a4c -[NSManagedObjectContext _processRecentChanges:]
19 CoreData 0x91494 -[NSManagedObjectContext _coreMergeChangesFromDidSaveDictionary:usingObjectIDs:withClientQueryGeneration:]
20 CoreData 0x90334 -[NSManagedObjectContext mergeChangesFromContextDidSaveNotification:]
21 CoreData 0x270dc developerSubmittedBlockToNSManagedObjectContextPerform
22 libdispatch.dylib 0x3dd4 _dispatch_client_callout
23 libdispatch.dylib 0x125a4 _dispatch_main_queue_drain
24 libdispatch.dylib 0x121b8 _dispatch_main_queue_callback_4CF
25 CoreFoundation 0x56710 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__
26 CoreFoundation 0x53914 __CFRunLoopRun
27 CoreFoundation 0x52cd8 CFRunLoopRunSpecific
28 GraphicsServices 0x11a8 GSEventRunModal
29 UIKitCore 0x40a90c -[UIApplication _run]
30 UIKitCore 0x4be9d0 UIApplicationMain
31 Rainbow 0x80c0 main + 15 (main.swift:15)
32 ??? 0x1b3419e4c (Mancante)
Core Data
RSS for tagSave 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
Good morning,
I've developed an application in order to show the information stored into a CoraData Table on a CollectionView through a NSFetchedResultsController. Several times I got this issue, is there anyone who can help me to understand the reason why this happens?
Thanks indeed.
Fatal Exception: NSInvalidArgumentException
0 CoreFoundation 0x83f20 __exceptionPreprocess
1 libobjc.A.dylib 0x16018 objc_exception_throw
2 CoreFoundation 0x1b6250 _NSArrayRaiseInsertNilException
3 CoreFoundation 0x16f5c -[__NSCFArray objectAtIndex:]
4 CoreData 0x13af14 -[_PFMutableProxyArray subarrayWithRange:]
5 CoreData 0xc4948 -[_NSDefaultSectionInfo objects]
6 CoreData 0x9c3fc -[NSFetchedResultsController _conditionallyDispatchSnapshotToDelegate:updatesInfo:]
7 CoreData 0x6d4ec __82-[NSFetchedResultsController(PrivateMethods) _core_managedObjectContextDidChange:]_block_invoke
8 CoreData 0x270dc developerSubmittedBlockToNSManagedObjectContextPerform
9 CoreData 0x9d0ec -[NSManagedObjectContext performBlockAndWait:]
10 CoreData 0x9c6e8 -[NSFetchedResultsController _core_managedObjectContextDidChange:]
11 CoreFoundation 0x5178c CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER
12 CoreFoundation 0x516a8 ___CFXRegistrationPost_block_invoke
13 CoreFoundation 0x515f0 _CFXRegistrationPost
14 CoreFoundation 0x4fbb8 _CFXNotificationPost
15 Foundation 0x31574 -[NSNotificationCenter postNotificationName:object:userInfo:]
16 CoreData 0x6a548 -[NSManagedObjectContext _createAndPostChangeNotification:deletions:updates:refreshes:deferrals:wasMerge:]
17 CoreData 0x69d10 -[NSManagedObjectContext _postRefreshedObjectsNotificationAndClearList]
18 CoreData 0x68a4c -[NSManagedObjectContext _processRecentChanges:]
19 CoreData 0x91494 -[NSManagedObjectContext _coreMergeChangesFromDidSaveDictionary:usingObjectIDs:withClientQueryGeneration:]
20 CoreData 0x90334 -[NSManagedObjectContext mergeChangesFromContextDidSaveNotification:]
21 CoreData 0x270dc developerSubmittedBlockToNSManagedObjectContextPerform
22 libdispatch.dylib 0x3dd4 _dispatch_client_callout
23 libdispatch.dylib 0x125a4 _dispatch_main_queue_drain
24 libdispatch.dylib 0x121b8 _dispatch_main_queue_callback_4CF
25 CoreFoundation 0x56710 CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE
26 CoreFoundation 0x53914 __CFRunLoopRun
27 CoreFoundation 0x52cd8 CFRunLoopRunSpecific
28 GraphicsServices 0x11a8 GSEventRunModal
29 UIKitCore 0x40a90c -[UIApplication _run]
30 UIKitCore 0x4be9d0 UIApplicationMain
31 Cloud 0x80c0 main + 15 (main.swift:15)
32 ??? 0x1b3419e4c (Mancante)
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()
}
}
I'm experiencing a new error in SwiftData since updating to Xcode 16/iOS 17 DB1. When passing in a model (Student) to a view and then displaying an array of Points using ForEach, I get the following fatal error:
SwiftData/ModelCoders.swift:2438: Fatal error: Failed to locate relationship for StringCodingKey(stringValue: "group", intValue: nil) on Entity - name: Point
superentity:
subentities:
storedProperties:
CompositeAttribute - name: type, options: [], valueType: PointType, defaultValue: nil
Properties:
Attribute - name: type, options: [], valueType: String, defaultValue: nil, hashModifier: nil
Relationship - name: outcome, options: [], valueType: Outcome, destination: Outcome, inverseName: nil, inverseKeypath: nil
CompositeAttribute - name: proficiency, options: [], valueType: Proficiency, defaultValue: nil
Properties:
Attribute - name: proficiency, options: [], valueType: String, defaultValue: nil, hashModifier: nil
Attribute - name: date, options: [], valueType: Date, defaultValue: nil, hashModifier: nil
Attribute - name: note, options: [], valueType: String, defaultValue: nil, hashModifier: nil
Relationship - name: student, options: [], valueType: Optional<Student>, destination: Student, inverseName: points, inverseKeypath: Optional(\Student.points)
Attribute - name: group, options: [], valueType: Array<PersistentIdentifier>, defaultValue: [], hashModifier: nil
inheritedProperties:
uniquenessConstraints:
indices:
Xcode flags this line of the macro-generated getter of the outcome property on Point:
@storageRestrictions(accesses: _$backingData, initializes: _outcome)
init(initialValue) {
_$backingData.setValue(forKey: \.outcome, to: initialValue)
_outcome = _SwiftDataNoType()
}
get {
_$observationRegistrar.access(self, keyPath: \.outcome)
return self.getValue(forKey: \.outcome) // Fatal error: Failed to locate relationship for StringCodingKey...
}
set {
_$observationRegistrar.withMutation(of: self, keyPath: \.outcome) {
self.setValue(forKey: \.outcome, to: newValue)
}
}
This worked just fine in iOS 17. Here's a snippet of the Student implementation:
@Model
class Student: Identifiable, Comparable {
var name: String
var number: Int
@Relationship(deleteRule: .cascade, inverse: \Point.student) var points: [Point]
@Relationship(deleteRule: .cascade, inverse: \Mark.student) var marks: [Mark]
@Relationship(deleteRule: .nullify, inverse: \StudentGroup.students) var groups: [StudentGroup] = []
var archived: Bool
}
and the implementation of Point:
@Model
class Point: Identifiable, Comparable {
var student: Student?
var type: PointType
var outcome: Outcome
var proficiency: Proficiency
var group: [Student.ID] = []
var date: Date
var note: String
}
and finally the implementation for Outcome:
@Model
class Outcome: Identifiable, Comparable {
var name: String
var index: Int
var rubric: Rubric?
var proficiencies: [Proficiency]
}
I've tried adding a relationship in Outcome as an inverse of the outcomes property on Points (although this does not make sense in my implementation, which is why I initially did not set a relationship here) and the problem persisted.
Any ideas what this error means and how I might go about fixing it?
In Core Data, you can use a pinned query generation to make sure that your app is working from a consistent view of the data store. If you have CloudKit sync turned on, and new changes come in that invalidate relationships, your app won't see them right away as long as it's looking at a pinned query generation.
Since Swift Data doesn't yet support query generations, how do I deal with this issue in Swift Data apps?
For example, let's say I have an address book app. I open a particular contact, and then tap a control on the screen that opens a list of images for that contact. While looking at the images, CloudKit sync retrieves changes made by other devices, which have completely removed the parent contact.
How does my app know this has happened? Suppose the image browser screen needs to refer to the parent contact, or make changes to it, but the contact is no longer there because a background sync removed it.
Recently, I noticed many crashes reported daily for context.save() in my code. I tried to resolve the issue by refactoring some of the code. My key change is to use context.performAndWait to fetch Core Data objects instead of passing them around.
I refactored the code to pass NSManagedObjectID around instead of NSManagedObject itself because NSManagedObjectID is thread-safe.
However, even after the refactor, the issue is still. The crash log is attached as below.
I'm confused that it doesn't crash on all devices so I have no clue to find the pattern of the crashes. I also enabled -com.apple.CoreData.ConcurrencyDebug 1 on my local dev box, but seems the error cannot be caught.
The new code (after I refactored) still causes the crash:
private func update(movements: [InferredMovement], from visitOutObjectId: NSManagedObjectID, to visitInObjectId: NSManagedObjectID?) {
let context = PersistenceController.shared.container.viewContext
context.performAndWait {
guard let visitOut = try? context.existingObject(with: visitOutObjectId) as? Visit else {
return
}
var visitIn: Visit?
if let visitInObjectId {
visitIn = try? context.existingObject(with: visitInObjectId) as? Visit
}
visitOut.movementsOut.forEach { context.delete($0) }
visitIn?.movementsIn.forEach { context.delete($0) }
for inferred in movements {
let movement = Movement(context: context)
movement.type = inferred.type
movement.interval = inferred.interval
movement.visitFrom_ = visitOut
movement.visitTo_ = visitIn
}
visitOut.objectWillChange.send()
context.saveIfNeeded()
}
}
Note, saveIfNeeded() is an extension function implemented as:
extension NSManagedObjectContext {
/// Only performs a save if there are changes to commit.
@discardableResult
public func saveIfNeeded() -> Error? {
guard hasChanges else {
return nil
}
do {
try save()
return nil
} catch {
defaultLogger.error("Core Data Error: Failed to save context")
return error
}
}
}
Crash context
I’m trying to sync data from the AppData on one device to another device with the same iCloud. It uploads the data to the CloudKit but it doesn’t write the data it fetches from the cloud into the AppData storage.
It should store a timestamp, a few integers, and two lists of integers. The lists are both optional and store numbers. They can have 0 up to 50 numbers in them.
This is the part where it should fetch the records and store them in the AppData
let container = CKContainer(identifier: "iCloud.com.calchunt")
let privateDatabase = container.privateCloudDatabase
let dispatchGroup = DispatchGroup()
var errors: [Error] = []
// Leere Liste zum Speichern neuer Spielsitzungen aus der Cloud
var newGameSessions: [AppModule.GameSession] = []
for gameSession in gameSessions {
let recordIDString = gameSession.id.uuidString // UUID zu String umwandeln
let recordID = CKRecord.ID(recordName: recordIDString)
dispatchGroup.enter()
privateDatabase.fetch(withRecordID: recordID) { (existingRecord, error) in
defer { dispatchGroup.leave() }
if let error = error {
// Fehler beim Abrufen des Records
print("Fehler beim Abrufen des Records aus CloudKit: \(error.localizedDescription)")
errors.append(error)
} else if let existingRecord = existingRecord {
// Record existiert in der Cloud
print("Record mit ID \(existingRecord.recordID.recordName) existiert in CloudKit")
// à berprüfen, ob der Record bereits im AppModule vorhanden ist
if let _ = gameSessions.firstIndex(where: { $0.id == gameSession.id }) {
// Record existiert bereits im AppModule, überspringe das Speichern
print("Record mit ID \(existingRecord.recordID.recordName) existiert bereits im AppModule, überspringe das Speichern")
} else {
// Record existiert nicht im AppModule, füge ihn zur Liste der neuen Spielsitzungen hinzu
let newGameSession = AppModule.GameSession(
id: gameSession.id,
losungszahl: gameSession.losungszahl,
elapsedTime: gameSession.elapsedTime,
currentDate: gameSession.currentDate,
skipped: gameSession.skipped,
skipped2: gameSession.skipped2,
level: gameSession.level
)
newGameSessions.append(newGameSession)
print("Record mit ID \(existingRecord.recordID.recordName) wird zum AppModule hinzugefügt")
}
} else {
// Record existiert nicht in der Cloud
print("Record mit ID \(recordID.recordName) existiert nicht in CloudKit")
}
}
}
dispatchGroup.notify(queue: .main) {
if !errors.isEmpty {
for error in errors {
print("Fehler beim Abrufen der Daten aus CloudKit: \(error.localizedDescription)")
}
} else {
// Füge neue Spielsitzungen zum AppModule hinzu
gameSessions.append(contentsOf: newGameSessions)
// Speichere die aktualisierten Daten im AppStorage
do {
let encoder = JSONEncoder()
let gameSessionsData = try encoder.encode(gameSessions)
GameSessions = gameSessionsData
print("Daten erfolgreich aus CloudKit geladen und im AppStorage gespeichert")
} catch {
print("Fehler beim Codieren und Speichern der Daten im AppStorage: \(error.localizedDescription)")
}
}
}
}
Using an @FetchRequest in my SwiftUI-redesigned app, I was looking to improve performance of my search and filtering on a List that has potentially a large amount of data. One of the things I was asking about was how to load some data initially and then fetch additional objects as the user scrolls.
In a WWDC lab today, while viewing my code the Apple engineer noted I had set a .fetchLimit on my FetchRequest, and suggested that I should be setting a .fetchBatchSize. It sounded like that was designed to do exactly what I wanted.
However, having attempted this, I can see from the console output that when I set a .fetchBatchSize of 50 and go to the view, it immediately loops through the entire collection of thousands of objects, attempting to load them into memory, and as some contain images this eventually crashes with an out of memory error.
This data is presented in a List. Originally, inside that list there was a ForEach inside that list but the same problem was seen when I removed the ForEach and used:
List(entries) { entry in
if let entryData = viewModel.entryData(for: entry) {
TimelineEntryView(entryData: entryData)
}
}
Can you advise on what might be going on here? I recall that in the previous iteration of my app, in UIKit and using an NSFetchedResultsController I had the exact same symptom: setting a fetch batch size immediately traversed the whole collection in the datastore, leading to terrible performance rather than the hoped-for good performance. So I did not set a batch size then either.
Am I holding this wrong? Is there something that might be triggering this?
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?
I have a large model. Not just large in complexity but literally there are gigabytes in the average user db.
I want to enable saving data to this model from app extensions. However, I do not want to duplicate code or model setup.
Is it recommended that I migrate to using a shared group model? How do you migrate existing stores to using shared containers?
Or are there better ways to do it? For example, should I create a brand new store that uses a shared container?
What are best practices?
Hi,
I updated my iPad to iOS18 beta 1, and it seems to crash my app immediately, even though it's the App Store release version that's running fine on iOS17. The crash report points to some issue in NSManagedObjectContext performBlockAndWait:
Thread 2 name: Dispatch queue: NSManagedObjectContext 0x303498000: CJCloudKitItemsUploaderQueue
Thread 2 Crashed:
0 libsystem_kernel.dylib 0x1f1930254 __pthread_kill + 8
1 libsystem_pthread.dylib 0x2285fcef8 pthread_kill + 268
2 libsystem_c.dylib 0x1a9a76ad8 abort + 128
3 CJournal 0x105428818 0x104e28000 + 6293528
4 CJournal 0x1054261f4 0x104e28000 + 6283764
5 CoreFoundation 0x1a1c40a3c __handleUncaughtException + 660
6 libobjc.A.dylib 0x19eec8210 _objc_terminate() + 132
7 CJournal 0x1053f5ad0 0x104e28000 + 6085328
8 libc++abi.dylib 0x22852087c std::__terminate(void (*)()) + 16
9 libc++abi.dylib 0x228520820 std::terminate() + 108
10 libdispatch.dylib 0x1a99bd174 _dispatch_client_callout + 40
11 libdispatch.dylib 0x1a99cc7b8 _dispatch_lane_barrier_sync_invoke_and_complete + 56
12 CoreData 0x1a9c94a6c -[NSManagedObjectContext performBlockAndWait:] + 264
13 ContactsJournalDataKit 0x10643fb50 -[CJCloudKitModifyRecordsOperation createUnderlyingCKModifyRecordsOperationWithProcessList:withLimit:] + 408
14 ContactsJournalDataKit 0x10643f544 -[CJCloudKitModifyRecordsOperation main] + 848
15 Foundation 0x1a071e2e0 __NSOPERATION_IS_INVOKING_MAIN__ + 16
16 Foundation 0x1a071c530 -[NSOperation start] + 648
17 Foundation 0x1a07947a0 __NSOPERATIONQUEUE_IS_STARTING_AN_OPERATION__ + 16
18 Foundation 0x1a07943ec __NSOQSchedule_f + 172
19 libdispatch.dylib 0x1a99cc350 _dispatch_block_async_invoke2 + 148
20 libdispatch.dylib 0x1a99bd160 _dispatch_client_callout + 20
21 libdispatch.dylib 0x1a99c0610 _dispatch_continuation_pop + 596
22 libdispatch.dylib 0x1a99bfc40 _dispatch_async_redirect_invoke + 580
23 libdispatch.dylib 0x1a99cedf4 _dispatch_root_queue_drain + 392
24 libdispatch.dylib 0x1a99cf5f8 _dispatch_worker_thread2 + 156
25 libsystem_pthread.dylib 0x2285f9c40 _pthread_wqthread + 228
26 libsystem_pthread.dylib 0x2285f6488 start_wqthread + 8
Can anyone shed some light on this? I haven't rebuilt the app with Xcode 16 yet, just wanted to run the App Store version and see if it's compatible without doing anything.
For a bit of context, I store binary files of about 50KB in my Core Data. I noticed that enabling the "Allows External Storage" option doesn't seem to make any difference.
Additionally, how does this setting work with CloudKit when using NSPersistentCloudKitContainer?
Does this setting affect how the data is loaded into memory when accessed in Core Data in the app?
Thank you very much!
Hi, when setting up our Core Data stack in our iOS app (manually, with a NSManagedObjectModel/Context & NSPersistentStoreCoordinator) we have reports a rare bug we haven't been able to reproduce.
Occasionally when adding a persistent store we get a NSCocoaErrorDomain 256 error (NSFileReadUnknownError) with NSSQLiteErrorDomain=4618 in the user info. That's SQLITE_IOERR_SHMOPEN , which the SQLite docs describe this way:
I/O error within the xShmMap method on the sqlite3_io_methods object while trying to open a new shared memory segment
It seems to specifically /not/ be a SQLITE_FULL error.
Do you know what type of issue can cause this? Or where/how I can start tracking this down?
I have a native SwiftUI Mac app which is based off my iOS app and includes Core Data with iCloud sync. As per my understanding, when a user makes a change on one of the devices a remote notification is sent to the others. I have a widget which displays information from Core Data and the remote notification makes the widget update its information on the next timeline refresh without the user having to open the app manually.
My question is, if an app is closed on macOS so it's not even running in the Dock, do remote notifications work? This page says "the delegate receives this message when the application is running and a remote notification arrives for it". Does that mean the app won't receive remote CloudKit notifications when closed on macOS?
Hi,
does someone knows about the bug, that the NSPersistentCloudKitContainer doesn't return CKShares at the first time? Is this an intended behavior?
My current fix:
let container: NSPersistentCloudKitContainer = ....
// Fix begin
let managedObject = .... // Object which is in a share
let record = container.record(for: managedObject.objectID)
// Fix end
let shares = (try? container.fetchShares(in: nil)) ?? []
If I execute exactly the same code without the fix that I fetch the record first, then it returns 0 shares. With the fix it is currently 9 shares (the actual count of the shares).
Another fix:
let container: NSPersistentCloudKitContainer = ....
// Fix begin
let _ = try? container.fetchShares(in: nil)
Thread.sleep(forTimeInterval: 0.1)
// Fix end
let shares = (try? container.fetchShares(in: nil)) ?? []
For that fix it also returns at the second time the expected count of shares. But without the delay it returns also at the second time zero shares.
Anyone had the same problem and if so, how do you solve it correctly?
Thanks!
We started to see some crashes in our iOS app a few seconds after launch with the following reason:
Exception Type: EXC_CRASH (SIGILL)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Termination Reason: SIGNAL 4 Illegal instruction: 4
when calling [NSPersistentContainer loadPersistentStoresWithCompletionHandler:].
I've looked through Understanding the exception types in a crash report page, but couldn't find this type there.
Any ideas what could it be?
I recently converted a Core Data app to use CloudKit. Before the conversion, the sqlite file was around 25MB. After the conversion, the file grew to over one gigabyte. I ran sqlite3_analyzer on the new file and found that a single table, ANSCKRECORDMETADATA, used 95% of the storage, 998MB.
Is this to be expected? I confess that the conversion was a bit bumpy. Maybe I did something to create a monstrosity.
If not expected, should I revert to the old Core Data file, create a new CloudKit container, and repeat the conversion.
My app uses Core Data to store an synchronise the data. It runs on iOS, iPadOS and now WatchOS. The records are stored in the private and shared CloudKit database.
Running the app in developer mode, syncing is fine for all devices.
But as soon as I switch to production mode using TestFlight, the Watch only syncs the data of the shared records, while iPad and iPhone still are syncing all records (private and shared) correctly.
I run out of ideas where to search for the reason of this problem. I use one module to setup the persistent store for iOS, iPadOs and WatchOS.
Any ideas are well come.
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)?
SwiftData includes support for CloudKit sync. However, I don't see any way to add conflict resolution behavior. For example, if different devices set different values for a field, or if a relationship is orphaned because of a deletion on another device, the application has to handle this somehow.
In Core Data (which SwiftData wraps), you can handle this with the conflict resolution system (docs) and classes like NSMergePolicy.
Is any of this accessible in SwiftData? If not, how do you deal with conflicts when syncing a SwiftData model with the cloud?