I've had to rewrite my app to get widgets working properly, and I've got this project structure:
Main iOS app:
Bundle identifier = com.me.myapp
Contains:
Widget Extension:
Bundle identifier = com.me.myapp.widgets
Targets iOS 17
Provides widgets to iOS
Watch app:
Bundle identifier = com.me.myapp.watchapp
Contains:
Complications Extension (a Widget Extension):
Bundle identifier = com.me.myapp.watchapp.complications
Targets watchOS 10
Provides widgets to watchOS
On the Signing & Capabilities tab in Xcode 15, all four targets have:
Provisioning Profile: Xcode Managed Profile
Signing Certificate: Apple Development: My team
App Groups: all use the same one: group.com.me.myapp
I can build and deploy to a physical iPhone and Apple Watch, but the Watch app doesn't seem to be able to access the shared Core Data, which should be in the shared app group container.
When running the main iOS app, the store location is:
file:///private/var/mobile/Containers/Shared/AppGroup/189E5907-E6E4-4790-833F-06944E4FF5FF/data-model/TheDataModel
When running the widget extension, the store location is:
file:///private/var/mobile/Containers/Shared/AppGroup/189E5907-E6E4-4790-833F-06944E4FF5FF/data-model/TheDataModel
When I run the Watch app, the store location is different:
file:///private/var/mobile/Containers/Shared/AppGroup/55381E6D-410E-4322-93BA-64BD1933909E/data-model/TheDataModel
How do I get the Watch app to see the Core Data store from the main app? Do I have to replicate the store to that location every time something changes in the main app? Or do I have to go back to sending massive data sets as dictionaries/data via WatchConnectivity?
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
I'm building a macOS + iOS SwiftUI app using Xcode 14.1b3 on a Mac running macOS 13.b11. The app uses Core Data + CloudKit.
With development builds, CloudKit integration works on the Mac app and the iOS app. Existing records are fetched from iCloud, and new records are uploaded to iCloud. Everybody's happy.
With TestFlight builds, the iOS app has no problems. But CloudKit integration isn't working in the Mac app at all. No existing records are fetched, no new records are uploaded.
In the Console, I see this message:
error: CoreData+CloudKit: Failed to set up CloudKit integration for store: <NSSQLCore: 0x1324079e0> (URL: <local file url>)
Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service named com.apple.cloudd was invalidated: failed at lookup with error 159 - Sandbox restriction." UserInfo={NSDebugDescription=The connection to service named com.apple.cloudd was invalidated: failed at lookup with error 159 - Sandbox restriction.}
I thought it might be that I was missing the com.apple.security.network.client entitlement, but adding that didn't help.
Any suggestions what I might be missing? (It's my first sandboxed Mac app, so it might be really obvious to anyone but me.)
Hi,
in my Core Data model, I’m using Transformable to store values of different kinds to the same attribute (I’m creating a user generated filter for data, that could filter for Integers, Boolean or other values - to avoid creating attributes for each possible types i‘m using transformable Any).
now, while querying for these values, I’ve noticed that this attribute is never correctly evaluated, but is always false.
is it possible to query for Transformable or do I need to change my approach and create an attribute for each possible Type?
Hey,
I have an iOS/watchOS application that has been in the App Store since the beginning of last year (for reference: https://endsplus.com). Part of the functionality includes:
Create a Fixture on the Phone
Create Fixture on iOs
Fixture is saved to Core Data
Core Data syncs with CloudKit
WatchOs pulls down the record, updating a table of the same name
I can show the Fixtures on the Watch.
Track a game on the Watch and then save it.
Create a Game on WatchOS
Game is saved to Core Data
Core Data syncs with CloudKit
iOS pulls down the record, updating a table of the same name
I can show the games on the phone.
For reasons I am unable to work out syncing of core data tables between the phone and the watch has stopped working.
I know that the iOS coredata/cloudkit functionality is working as I can create a record on my physical phone, then run a simulator and log in with the same iCloud account and see the record.
But the functionality has stopped working for watchOS. I have added a new table to the Watch side that is not syncing to the Phone, but an existing table (Fixture) that has been working has also stopped syncing between the phone and the watch.
None of my Persistence/Core Data code has changed. My new table is associated with a Cloud Store, the same as my old table is.
What options are they available to me to try and debug this. The watchOs simulator doesn't seem to work with CloudKit, telling me it is not signed in.
I've tried looking at the CloudKit database logs, but obviously for security I can't see the data, but I can't see any errors from the watch.
I've uninstalled and re-installed the application (on the phone and the watch) numerous times, but that isn't working.
Does anyone have any ideas?
Thanks
This should be simple, but it's proving immensely difficult and annoying.
I have three targets in the project:
an iOS app written in Objective-C
a Watch App written in Swift/SwiftUI
a Widget Extension with my widgets and complications in, written in Swift/SwiftUI
I want to access the Core Data that's got all my app's data in it from the Widget Extension and Watch App. How do I do this? Every internet search result assumes all your targets are in Swift, and it's really not feasible for me to rewrite the entire app.
All three targets have the same App Group set up, and I can access UserDefaults in each target.
I have a CoreData.swift class in a shared folder, and it's a member of both the Watch App and Widget Extension targets. It has this in it:
lazy var persistentContainer: NSPersistentContainer = {
let storeURL = URL.storeURL(for: kAppGroup, databaseName: kCoreDataModel)
let storeDescription = NSPersistentStoreDescription(url: storeURL)
let container = NSPersistentContainer(name: kCoreDataModel)
container.persistentStoreDescriptions = [storeDescription]
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("CoreData: Failed to initialise Managed Object Model from url: \(storeURL), with error: \(error), \(error.userInfo)")
}
})
return container
}()
and the storeURL extension is:
public extension URL {
static func storeURL(for appGroup: String, databaseName: String) -> URL {
guard let fileContainer = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroup) else {
fatalError("CoreData: Shared file container could not be created.")
}
return fileContainer.appendingPathComponent("\(kCoreDataModel).sqlite")
}
}
To be clear, the main iOS app (in Objective-C) has created the Core Data model etc., and it all works fine. I just want to be able to access the data in that model from the other targets. (I only need read access.)
When I deploy to a device the stack looks like this:
NSURL *dataModelFolderURL = [[[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:kAppGroup] URLByAppendingPathComponent:kCoreDataFolder];
Is: /private/var/mobile/Containers/Shared/AppGroup/9F329A90-C897-4AA2-87DF-D98A9E85356A/data-model
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:kCoreDataModel withExtension:@"momd"];
Is: file:///private/var/containers/Bundle/Application/CA9E3697-C4C6-48CB-89EA-CC441A6F81AF/MyApp.app/TheDataModel.momd/
// Wait until we have the store, or fetches will sometimes return no data
[self performSelectorOnMainThread:@selector(getStore) withObject:nil waitUntilDone:YES];
storeURL = file:///private/var/mobile/Containers/Shared/AppGroup/9F329A90-C897-4AA2-87DF-D98A9E85356A/data-model/TheDataModel
I've tried getting the Swift targets to look in a bunch of different paths, but nothing works. When I try to get a count of objects in the Core Data I always get zero results.
The second of those outputs is from the bundle. I guess that's because the data model is held within the iOS app's structure? Does that make any difference? Should it be held somewhere else? If so, what should it be?
(Minor rant: There really should be an option in Xcode that says, "This core data is shared here, here and here, and all you need to do is type CoreData.getSomeData() and you're done", but no, we have to write boilerplate code for everything.)
Anyway... any help is appreciated.
Hello,
I recently published an app on the App Store. I see a crash log from one of my users, but don't understand the reason CoreData crashed. It was simply saving a single object, and all the properties of it are optional.
I am unable to reproduce the crash, and in the over 8 moths of development before release, I did not encounter this type of error.
Please provide assistance, or where I could do some more research. I included part of the crash log below.
Thank you very much.
Hardware Model: iPhone15,4
Process: Proaneer
Version: 1.0.3 (50)
AppStoreTools: 15A240a
AppVariant: 1:iPhone15,4:17
Code Type: ARM-64 (Native)
Role: Foreground
Parent Process: launchd [1]
Date/Time: 2023-10-01 09:14:05.6888 -0400
Launch Time: 2023-10-01 09:08:34.4421 -0400
OS Version: iPhone OS 17.0.2 (21A350)
Release Type: User
Baseband Version: 1.00.03
Report Version: 104
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Termination Reason: SIGNAL 6 Abort trap: 6
Terminating Process: Proaneer
Triggered by Thread: 0
Last Exception Backtrace:
0 CoreFoundation 0x19a4565e0 __exceptionPreprocess + 164 (NSException.m:249)
1 libobjc.A.dylib 0x192767c00 objc_exception_throw + 60 (objc-exception.mm:356)
2 CoreData 0x1a2609410 -[NSPersistentStoreCoordinator _introspectLastErrorAndThrow] + 120 (NSPersistentStoreCoordinator.m:0)
3 CoreData 0x1a24f3fbc __65-[NSPersistentStoreCoordinator executeRequest:withContext:error:]_block_invoke.541 + 680 (NSPersistentStoreCoordinator.m:0)
4 CoreData 0x1a24f3c2c -[NSPersistentStoreCoordinator _routeHeavyweightBlock:] + 264 (NSPersistentStoreCoordinator.m:641)
5 CoreData 0x1a24d05b4 -[NSPersistentStoreCoordinator executeRequest:withContext:error:] + 1048 (NSPersistentStoreCoordinator.m:2768)
6 CoreData 0x1a24d05d8 -[NSPersistentStoreCoordinator executeRequest:withContext:error:] + 1084 (NSPersistentStoreCoordinator.m:3425)
7 CoreData 0x1a24c1e84 -[NSManagedObjectContext save:] + 972 (NSManagedObjectContext.m:1625)
8 Proaneer 0x102f2e268 ContactListViewModel.saveContact(functionName:functionAction:count:) + 96 (ContactListViewModel + CRUD Ext..swift:151)
9 Proaneer 0x102f2e1e4 ContactListViewModel.createContact() + 2496 (ContactListViewModel + CRUD Ext..swift:50)
10 Proaneer 0x102f7e08c closure #1 in closure #1 in closure #2 in closure #1 in closure #5 in ContactListRootView.body.getter + 84 (ContactListRootView.swift:203)
The following error message
"SIGABRT: This NSPersistentStoreCoordinator has no persistent stores (device locked). It cannot perform a save operation"
has indicated need to provide for sequencing of the Core Data context saving operation.
We want to avoid .save() if locking is in flight, also postpone .save() until unlocking has completed.
Currently our .save() is bracket by do-catch block but this is notably not helping in the case of SIGABR signal
Given that our saving operations must take place synchronously,
what is the recommended practice to implement such sequencing with respect to locking / unlocking
In my app I have a defaultJournal: Journal, that automatically gets added on the user's device on launch. There should only be one "default" journal, and I know that deduplication as shown in the Apple Demo, is the correct approach to ensure this on multiple devices. Journal looks something like:
class Journal: NSManagedObject {
@NSManaged var isDefaultJournal: Bool
@NSManaged var entries: Set<JournalEntry>?
}
Since Journal has a relationship to entries, how can I deduplicate it ensuring that I don't orphan or delete the entries?
I am worried that the entries aren't guaranteed to be synced, when we discover a duplicate journal in processPersistentHistory.
This would lead to either orphaned or deleted entries depending on the deletion rule.
How can one handle deduplicating entities with relationships?
For example here is my remove function:
func remove(duplicateDefaultCalendarNotes: [Journal], winner: Journal, on context: NSManagedObjectContext) {
duplicateDefaultCalendarNotes.forEach { journal in
defer { context.delete(journal) }
// FIXME: What if all of the journal entries have not been synced yet from the cloud?
// Should we fetch directly from CloudKit instead? (could still lead to orphaned/deleted journal that have not yet been uploaded)
guard let entries = journal.entries else { return }
entries.forEach {
$0.journal = winner
}
}
}
A missing tag on a post isn't that bad, but deleting a user's journal is unacceptable. What is the best strategy to handle this?
I am using SwiftData for my model. Until Xcode 15 beta 4 I did not have issues. Since beta 5 I am receiving the following red warning multiple times:
'NSKeyedUnarchiveFromData' should not be used to for un-archiving and will be removed in a future release
This seems to be a CoreData warning. However, I am not using CoreData directly. I have no way to change the config of CoreData as used by SwiftData.
My model just uses UUID, Int, String, Double, some of them as optionals or Arrays. I only use one attribute (.unique).
Hi
I really don't understand.
I have a record type on CloudKit where I store some data and a corresponding entity on core data that I sync with CloudKit with a very basic routine
at some point I call this func:
func GetUserFromCoredata(userID:String)->UserEntity?
{
var fetched:[UserEntity]?=nil
let fetch = NSFetchRequest<UserEntity>(entityName:"UserEntity")
let predicate = NSPredicate(format:"TRUEPREDICATE")
fetch.predicate = predicate
fetch.affectedStores = [DBGlobals.localStore, DBGlobals.cloudStore]
do{
print("RICHIESTA FETCH UTENTI IN COREDATA")
fetched = try context.fetch(fetch)
}
catch{
fatalError("errore nel recupero dell'elenco utenti")
}
if let found = fetched
{
for el in found
{
if el.userID == userID
{
return el
}
}
}
return nil
}
As you can see nothing special. it is only a fetch made on two stores.
If I run the code 20 times 19 are good and 1 result in a fatal error with this text:
2023-06-28 17:56:49.684780+0200 xDeskApp[23313:2379150] -[__NSCFConstantString bytes]: unrecognized selector sent to instance 0x215632f50
2023-06-28 17:56:49.712724+0200 xDeskApp[23313:2379150] [error] error: SQLCore dispatchRequest: exception handling request: <NSSQLFetchRequestContext: 0x283d88000> , -[__NSCFConstantString bytes]: unrecognized selector sent to instance 0x215632f50 with userInfo of (null)
2023-06-28 17:56:49.974635+0200 xDeskApp[23313:2379150] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFConstantString bytes]: unrecognized selector sent to instance 0x215632f50'
*** First throw call stack:
(0x1bd4d4cb4 0x1b657c3d0 0x1bd649ab8 0x1bd4eb0e8 0x1bd551900 0x1c4c53594 0x1c4bdf848 0x1c4bdf4b0 0x1c4c81d80 0x1068fa038 0x10690b814 0x1c4c81c20 0x1c4bcef68 0x1c4bcee38 0x1c4bbe200 0x1c4bc9a78 0x1c4d3752c 0x1c4c02678 0x1c4bc86d8 0x1c4bbb9fc 0x1c4bb6b14 0x1c4cc97ec 0x104bf00b0 0x104bef860 0x104bee8f4 0x1c4f82ce8 0x1c4f82d8c 0x1c5068cac 0x1c4f1f3b0 0x1c4f11338 0x1c50689d4 0x1bd53dc04 0x1bd4ebcb4 0x1bd4eb6cc 0x1c4fcc800 0x10690b158 0x1068fa038 0x1069020b0 0x106902e28 0x10690fc74 0x21d250ddc 0x21d250b7c)
libc++abi: terminating due to uncaught exception of type NSException
(Recorded stack frame)
... and really, I can't understand.
the predicate is absolutely basic, the entity exist, here I am not syncing anything, just fetching the records in the two stores... what am I doing wrong? why 19 su 20 are good and one is catching this error?
I used a renaming identifier to rename an Entity Name, but it doesn't seem to work and it causes a crash at start during in-place migration.
How to rename an Entity Name when using NSPersistentCloudKitContainer?
I get this exception at start:
CloudKit integration forbids renaming 'OldEntityName' to 'NewEntityName'. Older devices can't process the new records.
Unresolved error Error Domain=NSCocoaErrorDomain Code=134110 "An error occurred during persistent store migration."
App is not in production, need a way to rename 'OldEntityName' to 'NewEntityName'. How to achieve this?
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.
Is there a way to use the icloud account from game center to save Core Data entities in Cloud Kit?
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.
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
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?
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)
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?
I have an iPhone app the uses CloudKit for Core Data syncing. I also have a companion Apple Watch app that syncs to the same CloudKit records. The watch can be used without the iPhone app as well but they both independently sync to the same CloudKit database. This works reasonably well. As soon as either app is opened, the CloudKit will pull down the latest records.
I'd like to add a watch complication that shows the state of the CloudKit records. I supported this by adding a Widget extension, embedded in my watch app. The Core Data database in the watch app is part of an app group, so the complication is able to query the same database. So far so good.
I'm running into problems with the complication updating after remote records are changed from the iPhone. Here is what is happening:
When records are changed on the iPhone, the data syncs to CloudKit but the watch app is not updated when in the background. This is noticed when you open the app and it takes a second for the view to show the new records.
Since Core Data database on the watch is not being updated while in the background, the complication is not being updated at all.
Part of my confusion is I assumed CloudKit was meant to make this more seamless with silent push notifications? I have the "Remote Notifications" capability enabled on my WatchApp. It seems that only works while the app is in the foreground though. This seems very limiting when you have a complication that depends on the Watch app's Core Data state.
I have a few things to work around this with mixed success:
"Wake" the watch app explicitly when records are changed on the iPhone app using WatchConnectivityManager. The hope is that by waking the watch app, it will sync with iCloud. This either isn't working or intermittenly works. It is also not clear to me that by activating the watch app, that it will trigger records to sync. I wish there were a way to ask Core Data to sync explicitly.
Whenever the Apple watch app wakes in the last step, ask it to WidgetCenter to reload the widget.
This process feels convoluted and seems to negate some of the the benefits of CloudKit to synchronize data which I thought would be baked into this process.
Any thoughts on a better approach to all this?