Is there a way to use the icloud account from game center to save Core Data entities in Cloud Kit?
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
Hello,
I am using NSBatchInsertRequest to insert 5-6k items. With the release of iOS 17, I've encountered issues with populating optional fields. In cases where an optional field is nil, the field gets filled with a value from another message where this field is present.
Hello!
I was wondering if there's any open source example how to implement SUBQUERY in CoreData in calendar based app?
For example:
User creates an event with subtasks on the 1st on September with daily frequency
On the 5th of September they update just that day event's details, some subtasks.
On the 7th of September they see the same event that was created on the 1st of September.
Structs that can describe the case may look like this:
enum Frequency {
case daily
case weekly
case monthly
}
struct Subtask {
var name: String
var isCompleted: Bool
}
struct Event {
var id: UUID
var name: String
var startAt: Date
var repeatUntil: Date?
var isCompleted: Bool
var subtasks: [Subtask]
var frequency: Frequency?
var excludedOn: [Date]
}
For each day on a week I need to fetch events from CoreData, so I'm wondering how predicate can look like in such case?
I met SUBQUERY, but I'm not sure how to apply weekly and monthly frequency frequency into NSPredicate (for daily it's pretty straightforward).
Would be glad for any advices!
~Paul
I've encountered a significant sync issue with watchOS 10 RC on every device combination I've tested, running both iOS 17 and watchOS 10. I'm curious if others have noticed a similar problem.
Context:
Standalone watchOS app developed in SwiftUI with a companion iOS app.
Both apps use NSPersistentCloudKitContainer for bi-directional CloudKit CoreData Sync between the iOS app and watch.
Previously, this sync mechanism was near instant in the foreground and took max 1-2 minutes in the background
NSPersistentCloudKitContainer has been reliable since the app was first developed in the watchOS 6/iOS 13 era.
Issue:
In watchOS 10 RC, sync can take hours--and doesn't even occur when the app is in the foreground.
Sync only reliably happens when the watch is placed on the charger, seemingly only if the charge is over 50%.
Once taken off the charger, the watch will continue push and receive CoreData changes briefly before becoming unresponsive to sync again.
Additional Info:
The problem persists even when recompiled with the latest Xcode RC.
It's problem is consistent in both production and development CloudKit environments.
The CloudKit log shows no watch activity upon CoreData object updates, until placed on the charger (with over 50% charge). The sync starts in the background while the watch is charging.
The iOS app, however, reflects immediate activity in the CloudKit log after a CoreData change from the device and reacts promptly to pushes when they eventually occur from the watch.
The NSPersistentCloudKitContainer code hasn't changed since it was implemented.
Background modes for remote notifications are set correctly, and when sync finally happens, it's accurate.
I'm stumped. Perhaps there's a new watchOS 10 setting affecting CloudKit sync QoS? Or could this be a known watchOS 10 RC bug?
I have a Core Data container with two entities, a Category and an Item. The Item can have one Category assigned and the Category can be assigned to many Items.
What I need to do is group the items by category in a list in SwiftUI.
The code below doesn't group all items by category, it only shows one item by category. How can I group all items that have the same category assigned under the same category group?
Core Data Entities
Category
Attributes
name
Relationship
items (Type: To Many)
Item
Attributes
name
Relationship
category (Type: To One)
Swiftui
struct ItemsView: View {
let selectedList:List
@EnvironmentObject private var itemSM: ItemServiceModel
var body: some View {
List {
ForEach(itemSM.items) { item in
Section(header: Text(item.category?.name ?? "")) {
ForEach(itemSM.items.filter { $0.category == item.category }) { filteredItem in
Text("\(filteredItem.name ?? "")")
}
}
}
}
.onAppear{
itemSM.loadItems(forList: selectedList)
}
}
}
Service Item Service Model
class ItemServiceModel: ObservableObject{
let manager: CoreDataManager
@Published var items: [Item] = []
func loadItems(forList list: List){
let request = NSFetchRequest<Item>(entityName: "Item")
let sort = NSSortDescriptor(keyPath: \Item.name, ascending: true)
request.sortDescriptors = [sort]
let filter = NSPredicate(format: "list == %@", list)
request.predicate = filter
do{
items = try manager.context.fetch(request)
}catch let error{
print("Error fetching items. \(error.localizedDescription)")
}
}
}
This is what I see, as you can see, only one Fruits & Vegetables section should exist.
When using CloudKit in an app, if there are data changes on other devices being synchronized, and you also want to make changes to the data on the current device and reflect it back to the CloudKit server, you might want to display a native loading icon, like the one you see in the Notes app, during this process. How can you implement this? If anyone knows how to do it using SwiftUI, please let me know.
I've got
@Environment(\.managedObjectContext) var context
private var home: Home
private var predicate: NSPredicate
@State var sortBy: SortDescriptor<Room>
@FetchRequest private var rooms: FetchedResults<Room>
init(home: Home) {
self.home = home
_sortBy = State(initialValue: SortDescriptor<Room>(\.name))
self.predicate = NSPredicate(format: "%K = %@", "home", self.home)
_rooms = FetchRequest<Room>( sortDescriptors: [self.sortBy], predicate: self.predicate)
}
But it won't compile -- it says Variable 'self.rooms' used before being initialized. But... how?
I have an existing iOS/watchOS app that uses a third-party database and WatchConnectivity. For various reasons I am migrating the app to use Core Data with CloudKit.
I have everything working using NSPersistentCloudKitContainer. Sync between the iOS and watchOS app are working on my test devices when I start with an empty database.
However, I need to import existing user's data when they first install this new version. Some users may have hundreds or thousands of records, but the total database size is under 1-2MB.
Data migration/import is working on the iOS side, the Core Data entities are populated on first launch and uploaded to CloudKit (I see in the debug logs that a NSPersistentCloudKitContainer.Event export ends successfully).
The problem is launching the watchOS app does not sync the data from CloudKit. I see a import started event but never see it end. I never see any Core Data entities appear on watchOS even after waiting several minutes and re-opening the Watch app multiple times. New entities or modifications made on either app are also not synced.
Is the problem just too much data which causes the CloudKit sync to never finish?
What are the best practice to populate a watchOS app with initial data from the parent iOS app and keep it in sync with CoreData/CloudKit?
With the following code:
@Model
final class Item {
var data: [Data]
init(data: [Data]) {
self.data = data
}
}
@Model
final class Data {
var contents: String
init(contents: String) {
self.contents = contents
}
}
..
let data = Data(contents: "yo")
let newItem = Item(timestamp: Date(), data: [data])
print(newItem.data) // <-- exception thrown here
I get an exception on the print line when accessing the .data field:
Thread 1: EXC_BREAKPOINT (code=1, subcode=0x1f379a29c)
Note that if I first save newItem to the context the exception is not thrown, i.e.:
let data = Data(contents: "yo")
let newItem = Item(timestamp: Date(), data: [data])
modelContext.insert(newItem)
print(newItem.data) // <-- no exception
Unfortunately the exception is cryptic so I can't tell what's wrong.
Xcode version 15.0 beta 8 (15A5229m)
macOS Sonoma beta 14.0 (23A5337a)
Hello. I had some problems related to objectID, let me try to describe it.
I had 3 managed object contexts:
context A - root private context of persistentCoordiantor, used for write changes to persistentStore. retainsRegisteredObjects = false
context B - main context, parent context - A. retainsRegisteredObjects = true
context C - background private context. parent context - B. retainsRegisteredObjects = true
When I add new MO to coreData, it saved succesfully to all contexts , but, when I check registeredObjects of context B and C, objectID for new MO is temporary, this is problem for me, because I had some work with coreData from NotificationServiceExtension, and I use fetch persistent history to get updates that was made in NSE and apply them to main app, but, in fetch history I get changes for MO that have permanentID, but in my context B and C there is still temporaryID. It was strange for me, so, I set retainsRegisteredObjects to context A, after that, I noticed, that after save new MO to coreData, permanentID is set only in context A for that MO, in contexts B and C MO still have temporaryID, does it correct behaviour of coreData or it's bug?
I expect that when I save MO to coreData, it will automatically update ID as permanent for MO in all context for this MO if it exist in registeredObjects of certain context
My code to show a list from a fetch that can be selected is (simplified) as follows
@FetchRequest(sortDescriptors: []) private var players: FetchedResults<PlayerEntity>
@State private var selectedPlayerID : PlayerEntity.ID?
var body: some View {
NavigationSplitView {
List(players, selection: $selectedPlayerID) { player in
Text(player.shortName ?? "")
}
.navigationTitle("Players")
} detail: {
if let id = selectedPlayerID, let player = players.first(where: {$0.id == id}) {
Text("Do Something")
}
}
}
I'm using the state variable of type ID PlayerEntity.ID? to hold the selection.
However, I noticed the sample app from migrating to SwiftData ("SampleTrips") is essentially doing it like this:
@FetchRequest(sortDescriptors: [SortDescriptor(\.startDate)])
private var trips: FetchedResults<Trip>
@State private var showAddTrip = false
@State private var selection: Trip?
@State private var path: [Trip] = []
var body: some View {
NavigationSplitView {
List(selection: $selection) {
ForEach(trips) { trip in
TripListItem(trip: trip)
//... removed some extra code
}
}
//... removed some extra code
.navigationTitle("Upcoming Trips")
//... removed some extra code
} detail: {
if let selection = selection {
NavigationStack {
TripDetailView(trip: selection)
}
}
}
The sample code is able to pass an optional managed object type Trip? to hold the selection rather than the ID type. When I try to replicate that behavior, I can't. Does anyone know what would be different?
i need to make app that make Database of received Serial data
after receiving data , i need to show data using chart.
Serial data traffic is not high, and is not happen frequently...
and can i use FMDB at SwiftUI ?
I've successfully followed the sample code from Apple: Synchronizing a local store to the cloud to deduplicate entities that are created in the user's private store.
However my app also has a public store that needs deduplication and if I enable the NSPersistentStoreRemoteChangeNotificationPostOptionKey for both the private and public store then no deduplication will occur in my private store.
This is reproducible every time by not setting NSPersistentStoreRemoteChangeNotificationPostOptionKey for the public store.
Has anyone else experienced this and has anyone got a solution to get it to work?
Persistence setup code:
private static func makeStoreDescription(for database: Database) -> NSPersistentStoreDescription {
let url: URL
let scope: CKDatabase.Scope
let configuration: String
switch database {
case .private:
url = Self.privateStoreURL
scope = .private
configuration = "Private"
case .public:
url = Self.publicStoreURL
scope = .public
configuration = "Public"
}
let storeDescription = NSPersistentStoreDescription(url: url)
storeDescription.cloudKitContainerOptions = .init(containerIdentifier: Config.cloudKitContainerIdentifier)
storeDescription.cloudKitContainerOptions?.databaseScope = scope
switch database {
case .private:
storeDescription.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
storeDescription.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
case .public:
// Uncommented otherwise deduplication doesn't work
// storeDescription.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
// storeDescription.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
break
}
storeDescription.configuration = configuration
return storeDescription
}
private static func makeContainer(inMemory: Bool = false, useIcloud: Bool) -> NSPersistentCloudKitContainer {
let privateStoreDescription = makeStoreDescription(for: .private)
let publicStoreDescription = makeStoreDescription(for: .public)
let container = NSPersistentCloudKitContainer(name: "Name", managedObjectModel: managedObjectModel)
container.persistentStoreDescriptions = [privateStoreDescription, publicStoreDescription]
// Don't save information for future use if running in memory...
if inMemory {
container.persistentStoreDescriptions.forEach { $0.url = URL(fileURLWithPath: "/dev/null") }
}
print("useIcloud:", useIcloud)
if !useIcloud {
container.persistentStoreDescriptions.forEach { $0.cloudKitContainerOptions = nil }
}
container.loadPersistentStores { storeDescription, error in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
print("Loaded store configuration:", storeDescription.configuration ?? "")
}
#if DEBUG
// Use the container to initialize the development schema.
// Only necessary whenever changes have been made to the schema.
//try! container.initializeCloudKitSchema(options: [])
#endif
container.viewContext.automaticallyMergesChangesFromParent = true
container.viewContext.mergePolicy = NSMergePolicy.mergeByPropertyObjectTrump
container.viewContext.transactionAuthor = Self.transactionAuthor
if !inMemory {
do {
try container.viewContext.setQueryGenerationFrom(.current)
} catch {
fatalError("Failed to pin viewContext to the current generation: \(error)")
}
}
return container
}
Does the Reminders app use Core Data with CloudKit behind the scenes? I would like to know what approach is used to allow for re-ordering items and how conflicts are handled when move operations are done from multiple offline devices.
I need some help understanding how the public database works in CloudKit. First of all, let me say that I know how to connect and use the private database. In this question I'm not looking for an answer on how to connect to the database at self, only the concept. Here is my confusion. I have a set of images that all users in my app will be using, right now what I'm doing is adding the images directly to the app (an Image Set in Xcode) and then I am pulling them to Core Data and then syncing them to CloudKit. As you can see all images are technically stored in every device using my app and in Core Data/CloudKit, not very efficient. What I would like is to have the images stored in a single place where all uses can pull the images from, in this case CloudKit. I know I can have them somewhere in a private server, but I feel like I would be adding more complexity to my app, so I think using CloudKit is a better option for me. Here is my question.
How do I get the images to CloudKit, do I upload them directly to CloudKit and then read from all devices or do I need to first add them to a device and upload to CloudKit from there?
Thanks!
Hello,
I am building a list in SwiftUI, using the @FetchRequest property wrapper to fetch core data entities, taking as input a fetch request which has the property fetchBatchSize set to 50.
import SwiftUI
import CoreData
extension Item {
static var listRequest: NSFetchRequest<Item> {
let request = Item.fetchRequest()
request.fetchBatchSize = 50
request.sortDescriptors = [NSSortDescriptor(keyPath: \Item.timestamp, ascending: true)]
return request
}
}
struct ContentView: View {
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(fetchRequest: Item.listRequest)
private var items: FetchedResults<Item>
var body: some View {
NavigationView {
List {
ForEach(items) { item in
Text(item.timestamp!, formatter: itemFormatter)
}
}
}
}
}
But when loading my list with 3000 items and having the argument -com.apple.CoreData.SQLDebug enabled, there are 241 calls made to load my items 50 by 50 at a time. There is no mention of fetchBatchSize in the documentation, but this feature of fetch request is really important to me when building App dealing with large datasets of objects.
Am I doing something wrong or is there any recommandation about large data sets performances with SwiftUI lists indicating the best practices?
Thanks for your help !
Hello everyone,
I'm a complete beginner when it comes to programming and have been learning Swift for the past 2-3 months. I'm in the process of writing my very first project, an Apple Watch app for Tesla owners.
So far, I've managed to complete the UI aspect of the app and have recently begun diving into the coding part. However, I find myself a bit lost when it comes to connecting my app to the unofficial Tesla API.
On top of that, I'm also wondering if integrating Core Data is necessary for this kind of project?
If anyone could help me by providing a clear roadmap, it would greatly accelerate my research and learning process. Any tips, tutorials, or resources you could point me toward would be immensely helpful.
Thanks in advance for your assistance!
Best Regards
Sasan
I'm having a weird issue. I have a watch app which communicates with the phone using a WCSessionDelegate.
if the phone app is open everything works fine, but if the app is closed, when the watch sends a message, my app is woken from the background, after which onAppear() is called in my app which causes a swiftData query to run.
Calling any swiftdata function from a backgrounded app causes it to immediately crash with the following stack trace. Any ideas what im doing wrong? or a better way to trigger my code instead of onAppear, so it won't be called when my watch wakes my app from the background?
.onAppear {
reloadData()
}
private func reloadData() {
let fetch = FetchDescriptor<SavedServer>(
predicate: nil,
sortBy: [.init(\.displayOrder)]
)
guard let results = try? modelContext.fetch(fetch) else {
self.rows = []
return
}
self.rows = results
}
-------------------------------------
Translated Report (Full Report Below)
-------------------------------------
Incident Identifier: 057999AF-7840-410E-B3EE-29082C5AED00
CrashReporter Key: 28AF2AA0-4626-9964-9664-36077DAF4E1A
Hardware Model: MacBookPro18,2
Process: MC Status [68915]
Path: /Users/USER/Library/Developer/CoreSimulator/Devices/C61698BA-C4CA-4DD9-B824-DBF57AC65090/data/Containers/Bundle/Application/A685371C-9174-4CF7-9E99-D573310CC3E5/MC Status.app/MC Status
Identifier: com.shemeshapps.MinecraftServerStatus
Version: 2.0 (1)
Code Type: ARM-64 (Native)
Role: Non UI
Parent Process: launchd_sim [55432]
Coalition: com.apple.CoreSimulator.SimDevice.C61698BA-C4CA-4DD9-B824-DBF57AC65090 [164301]
Responsible Process: SimulatorTrampoline [53834]
OS Version: macOS 13.4.1 (22F82)
Release Type: User
Report Version: 104
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Triggered by Thread: 0
Last Exception Backtrace:
0 CoreFoundation 0x18046589c __exceptionPreprocess + 160
1 libobjc.A.dylib 0x18005c09c objc_exception_throw + 56
2 CoreData 0x184989b94 -[NSFetchRequest(_NSInternalMethods) _incrementInUseCounter] + 0
3 CoreData 0x1849aa99c -[NSManagedObjectContext executeRequest:error:] + 164
4 CoreData 0x1848fe250 NSManagedObjectContext.fetch<A>(_:) + 80
5 SwiftData 0x1a89b7ad8 ModelContext.fetch<A>(_:) + 124
6 SwiftData 0x1a89c48c0 dispatch thunk of ModelContext.fetch<A>(_:) + 20
7 MC Status 0x102530ef4 MainAppContentView.reloadData(forceRefresh:) + 752 (MainAppContentView.swift:112)
8 MC Status 0x102533540 closure #2 in MainAppContentView.body.getter + 44 (MainAppContentView.swift:78)
9 SwiftUI 0x108a0b7a0 0x107b8c000 + 15202208
10 SwiftUI 0x108a0b7bc 0x107b8c000 + 15202236
11 SwiftUI 0x108a0b7a0 0x107b8c000 + 15202208
12 SwiftUI 0x108fdce70 0x107b8c000 + 21302896
13 SwiftUI 0x108fd6ec0 0x107b8c000 + 21278400
14 SwiftUI 0x1081edb24 0x107b8c000 + 6691620
15 SwiftUI 0x10928d650 0x107b8c000 + 24122960
16 libdispatch.dylib 0x1801424f4 _dispatch_call_block_and_release + 24
17 libdispatch.dylib 0x180143d3c _dispatch_client_callout + 16
18 libdispatch.dylib 0x180152b24 _dispatch_main_queue_drain + 1272
19 libdispatch.dylib 0x18015261c _dispatch_main_queue_callback_4CF + 40
20 CoreFoundation 0x1803c61b4 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 12
21 CoreFoundation 0x1803c08cc __CFRunLoopRun + 1936
22 CoreFoundation 0x1803bfd28 CFRunLoopRunSpecific + 572
23 GraphicsServices 0x189864bc0 GSEventRunModal + 160
24 UIKitCore 0x103b30208 -[UIApplication _run] + 868
25 UIKitCore 0x103b33e80 UIApplicationMain + 124
26 SwiftUI 0x108a10524 0x107b8c000 + 15222052
27 SwiftUI 0x108a103c4 0x107b8c000 + 15221700
28 SwiftUI 0x108722088 0x107b8c000 + 12148872
29 MC Status 0x102506d30 static MCStatusApp.$main() + 40
30 MC Status 0x102506de0 main + 12 (MCStatusApp.swift:12)
31 dyld_sim 0x1028fd558 start_sim + 20
32 dyld 0x1026b1f28 start + 2236
33 ??? 0x3c15800000000000 ???
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 libsystem_kernel.dylib 0x102f1cfa8 __pthread_kill + 8
1 libsystem_pthread.dylib 0x10285712c pthread_kill + 256
2 libsystem_c.dylib 0x1801375ec abort + 104
3 libc++abi.dylib 0x180263c78 abort_message + 128
4 libc++abi.dylib 0x180255198 demangling_terminate_handler() + 300
5 libobjc.A.dylib 0x180037bf0 _objc_terminate() + 124
6 libc++abi.dylib 0x180263150 std::__terminate(void (*)()) + 12
7 libc++abi.dylib 0x180263100 std::terminate() + 52
8 libdispatch.dylib 0x180143d50 _dispatch_client_callout + 36
9 libdispatch.dylib 0x180152b24 _dispatch_main_queue_drain + 1272
10 libdispatch.dylib 0x18015261c _dispatch_main_queue_callback_4CF + 40
11 CoreFoundation 0x1803c61b4 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 12
12 CoreFoundation 0x1803c08cc __CFRunLoopRun + 1936
13 CoreFoundation 0x1803bfd28 CFRunLoopRunSpecific + 572
14 GraphicsServices 0x189864bc0 GSEventRunModal + 160
15 UIKitCore 0x103b30208 -[UIApplication _run] + 868
16 UIKitCore 0x103b33e80 UIApplicationMain + 124
17 SwiftUI 0x108a10524 0x107b8c000 + 15222052
18 SwiftUI 0x108a103c4 0x107b8c000 + 15221700
19 SwiftUI 0x108722088 0x107b8c000 + 12148872
20 MC Status 0x102506d30 static MCStatusApp.$main() + 40
21 MC Status 0x102506de0 main + 12 (MCStatusApp.swift:12)
22 dyld_sim 0x1028fd558 start_sim + 20
23 dyld 0x1026b1f28 start + 2236
I have an app Im moving over to cloudkit and it works fine on a new instance, but updating to this instance causes a perpetual crash and requires reinstall. I know this is because the persistence object changed. I was just using a normal NSPersistentController now a CK one, and there are two persistent stores, the public and private stores. Is there a way to either migrate the data properly, or atleast wipe the data model before it crashes and have it start anew? (I dont have many users and I know them personally so this would be acceptable)
I am having trouble using UndoManager with a private Manged Object Context in CoreData. Here is my setup: I have my main context running on the main queue. I created a private context via let privateContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) and connect it as a child context to my main context via privateContext.parent = mainContext. I also assigned an UndoManager to privateContext. This UndoManger has been set to use manual grouping via undoManager.groupsByEvent = false. So far so good.
Now to the part that gives me trouble: I want to change something on the private context and record this action for potential undoing. In order to do this a use a nested grouping structure (that is how it makes sense in my code). This is how i currently do this:
privateContext.performAndWait {
undoManger.beginUndoGrouping
}
// do something in code unrelated to changes on the privateContext
privateContext.performAndWait {
doChangesOnPrivateContext()
}
privateContext.performAndWait {
undoManger.beginUndoGrouping
}
privateContext.performAndWait {
doChangesOnPrivateContext()
}
privateContext.performAndWait {
undoManger.endUndoGrouping
}
// do something in code unrelated to changes on the privateContext
privateContext.performAndWait {
undoManger.endUndoGrouping
}
This leads to the error:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '_setGroupIdentifier:: NSUndoManager is in invalid state, must begin a group before registering undo
which I had encountered before when beginUndoGrouping and endUndoGrouping were called from different threads. Further examination yields that this is also the case here as performAndWait runs the code on the private queue assigned to privateContext, but with the structure shown above beginUndoGrouping and endUndoGrouping are indeed called on different threads.
So here are my questions:
How do I do this correctly?
Do I misunderstand things and UndoMangager should not be used on a private context? If so, how would I setup things then?