Hello, how do I fix "Thread 1: "NSFetchRequest could not locate an NSEntityDescription for entity name 'Goal'"
import SwiftUI
import SwiftData
@main
struct Main: App {
@Environment(\.scenePhase) private var scenePhase
@StateObject var statsViewModel = StatsViewModel()
@StateObject var badgeViewModel = BadgeViewModel()
@StateObject var localNotificationManager = LocalNotificationManager()
@AppStorage("notifications") var notificationsSet: Bool = false
@Environment(\.modelContext) private var modelContext
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(statsViewModel)
.environmentObject(badgeViewModel)
.environmentObject(localNotificationManager)
.task {
if !notificationsSet {
do{
try await localNotificationManager.reqeustAuthorization()
await localNotificationManager.setUpNotificationsAtStart()
} catch{
}
}
notificationsSet = true
}
}
.modelContainer(container)
.onChange(of: scenePhase) { _, phase in
if phase == .active{
Task{
await localNotificationManager.getCurrentSettings()
await localNotificationManager.getPendingRequest()
}
} else if phase == .background{
do {
try modelContext.save()
} catch {
print("COULD NOT SAVE WITH SWIFTDATA")
}
}
}
}
}
and
@MainActor
var container: ModelContainer = {
let fileContainer = URL.storeURL(for: "group.Water-Alert-App", databaseName: "CoreData")
let defaultDirectoryURL = NSPersistentContainer.defaultDirectoryURL()
let localSchema = Schema([Reminder.self])
let cloudSchema = Schema([Goal.self, WaterData.self, Container.self])
let localConfiguration = ModelConfiguration("Local", schema: localSchema, url: defaultDirectoryURL.appendingPathComponent("Local.sqlite"))
let cloudConfiguration = ModelConfiguration("Cloud", schema: cloudSchema, url: fileContainer, cloudKitDatabase: .private("iCloud.Water-Alert-App-Offical"))
let container = try! ModelContainer(for: Reminder.self, Goal.self, WaterData.self, Container.self, configurations: localConfiguration, cloudConfiguration)
return container
}()
this is the code that makes the app crash
Thank You
Post
Replies
Boosts
Views
Activity
Hello
I have a CoreData PersistenceController and would like to convert it to a SwiftData container. Before converting the whole app to use SwiftData I wanted to know if my conversion is right and preserves old data (in iCloud and local).
Here is the code:
PersistenceController:
import CoreData
import SwiftUI
import Combine
#if os(iOS) || os(macOS) || os(watchOS)
import WidgetKit
#endif
struct PersistenceController {
static let shared = PersistenceController()
let container: NSPersistentCloudKitContainer
init() {
let fileContainer = URL.storeURL(for: "group.Water-Alert-App", databaseName: "CoreData")
container = NSPersistentCloudKitContainer(name: "CoreData")
let defaultDirectoryURL = NSPersistentContainer.defaultDirectoryURL()
let localStoreURL = defaultDirectoryURL.appendingPathComponent("Local.sqlite")
let localStoreDescription = NSPersistentStoreDescription(url: localStoreURL)
localStoreDescription.configuration = "Local"
// Create a store description for a CloudKit-backed local store
let cloudStoreDescription = NSPersistentStoreDescription(url: fileContainer)
cloudStoreDescription.configuration = "Cloud"
// Set the container options on the cloud store
cloudStoreDescription.cloudKitContainerOptions = NSPersistentCloudKitContainerOptions(containerIdentifier: "iCloud.namel")
cloudStoreDescription.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
cloudStoreDescription.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
container.persistentStoreDescriptions = [cloudStoreDescription, localStoreDescription]
container.loadPersistentStores{ (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
}
container.viewContext.automaticallyMergesChangesFromParent = true
container.viewContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy
}
func save() {
if container.viewContext.hasChanges {
do {
try container.viewContext.save()
} catch {
print("COULD NOT SAVE WITH CORE DATA")
}
}
}
}
ModelContainer:
var container: ModelContainer? = {
let fileContainer = URL.storeURL(for: "group.Water-Alert-App", databaseName: "CoreData")
let defaultDirectoryURL = NSPersistentContainer.defaultDirectoryURL()
let localSchema = Schema([Reminder.self])
let cloudSchema = Schema([Goal.self, WaterData.self, Container.self])
let localConfiguration = ModelConfiguration("Local", schema: localSchema, url: defaultDirectoryURL.appendingPathComponent("Local.sqlite"))
let cloudConfiguration = ModelConfiguration("Cloud", schema: cloudSchema, url: fileContainer, cloudKitDatabase: .private("iCloud.Water-Alert-App-Offical"))
let container = try! ModelContainer(for: Reminder.self, Goal.self, WaterData.self, Container.self, configurations: localConfiguration, cloudConfiguration)
return container
}()
Thank you!
Hello
Is there way to keep calling a function (efficiently) while the view is on screen, without using a timer, in SwiftUI?
Hello
@FetchRequest(
entity: Book(),
sortDescriptors: []
) var books: FetchedResults<Book>
How can I get notified when books changes?
I was thinking about putting this...
.onReceive(NotificationCenter.default.publisher(for: .NSManagedObjectContextDidSave), perform: { _ in})
... in my main View but this would notify me if anything gets saved and that is not what I want. I want to get notified just if a certain FetchRequest changes (in this case books)?
How can I do that?
Thank You!
Hello
I am building a study research app that tracks data of different users. The data is saved through Core Data (with relationships) and I was wondering if there was a way to view all the data through CloudKit?
I know I can use public databases with CloudKit in CoreData but was wondering if that would merge all the data of the different users, and if that is the case how would I deal with it?
If that is not possible how would I download all the data in a PDF that the user can send?
Thanks for your help
Hello
I'm building an indoor geofencing app with iBeacons.
I want to detect each time a user approaches a beacon and the distance and save this data with Core Data only if the distance (proximity) to the iBeacon is close.
I am using Core Location to do this but I am not using the didEnter / didExit functions as they do not provide the distance to the beacon. I am mainly using the didRange function from locationManager to get all the beacons, find the closest one and its distance.
This approach works perfectly while the app is in the foreground. However, the app starts not working properly in the background. If I just change the app, the didRange function stops working, but if I lock the phone and look at the time on the lock screen, it starts working. The problem is not that the app does not work in the background, but that the functions are activated only in specific cases or times, eg. the phone is locked.
I added these properties in the info.plist
Privacy - Location When In Use Usage Description
Privacy - Location Always and When In Use Usage Description
Required background modes:
Location updates
I also added this code:
locationManager.delegate = self
locationManager.allowsBackgroundLocationUpdates = true
locationManager.pausesLocationUpdatesAutomatically = false
This is how I add a beacon and start monitoring it:
func addBeacon(id: String, major: Int16 = 0, minor: Int16 = 0) {
guard let uuid = UUID(uuidString: id) else { return }
let region = CLBeaconRegion(uuid: uuid, major: CLBeaconMajorValue(major), minor: CLBeaconMinorValue(minor), identifier: id + major.description + minor.description)
region.notifyOnEntry = true
region.notifyOnExit = true
region.notifyEntryStateOnDisplay = true
self.locationManager.startMonitoring(for: region)
resetValues()
}
func locationManager(_ manager: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) {
let beaconRegion = region as! CLBeaconRegion
if state == .inside {
// Start ranging when inside a region.
manager.startRangingBeacons(satisfying: beaconRegion.beaconIdentityConstraint)
} else {
// Stop ranging when not inside a region.
manager.stopRangingBeacons(satisfying: beaconRegion.beaconIdentityConstraint)
}
}
I am also making sure that locationManager.requestAlwaysAuthorization() is always true
Do you have any ideas why it is not always working in the background?
Thanks for your time.
Hello
What is the best framework for indoor geofencing (with iBeacons devices)? Would the SensorKit framework be any good?
I'm trying to build an indoor geofencing app that uses UWB or BLE devices.
I am thinking of the SensorKit framework because it is used for research and studies and I am looking for the best way to realize indoor geofencing (preferably using UWB devices). The app should also work while it's in the background.
Thank you!
Hello
I'm trying to compose a layout using the Layout API.
I have already written the code for both the Layout Stack I want to use and the view I am using it in, however I am getting an "Extra trailing closure passed in call" error in the view I am using the Stack in.
Here is the code:
import SwiftUI
struct StairsView: View {
var body: some View {
Group{
MyStairsStack{
Text("Hello, World!")
Text("Hello, World!")
Text("Hello, World!")
}
}
}
}
struct MyStairsStack: Layout{
func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout Void) -> CGSize {
return .init(width: proposal.width ?? 0, height: proposal.height ?? 0)
}
func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout Void) {
guard !subviews.isEmpty else { return }
let viewSize = maxSize(subViews: subviews)
var origin = bounds.origin
let maxWidth = bounds.width
subviews.forEach { view in
if (origin.x + (viewSize.width + 10) >= maxWidth){
origin.x = bounds.origin.x
}
view.place(at: origin, proposal: proposal)
origin.x += (viewSize.width + 10)
origin.y += (viewSize.height + 10)
}
}
private func maxSize(subViews: Subviews) -> CGSize{
subViews.map { $0.sizeThatFits(.unspecified) }.reduce(.zero) { currentMax, subviewSize in
CGSize(
width: max(currentMax.width, subviewSize.width),
height: max(currentMax.height, subviewSize.height))
}
}
}
The error is at line 5
Thank You for your time
Hello
What would be the best and most efficient way to save photos and videos using Core Data knowing that they will be synced using CloudKit.
Thanks
Hello
How can I remove the Collapse button that is on the navigationBar in iPadOS?
Thank You!
Hello, I have created a simple SwiftUI app with Core Data and want to be able to add data via the shortcuts app, I have implemented Intents and the IntentHandler class. When I create a shortcut to add data to my app and run it, nothing happens in the app, the list does not refresh, the only way to see the added data is to close the app completely and reopen it. How can I refresh the UI immediately? I will post my Core Data stack and my SwiftUI view.
struct PersistenceController {
static let shared = PersistenceController()
let container: NSPersistentContainer
init() {
container = NSPersistentContainer(name: "SiriShort")
guard let fileContainer = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.SiriShortcut2")?.appendingPathComponent("SiriShort.sqlite") else {
fatalError("Shared file container could not be created.")
}
let storeDescription = NSPersistentStoreDescription(url: fileContainer)
storeDescription.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
storeDescription.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
container.persistentStoreDescriptions = [storeDescription]
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
container.viewContext.automaticallyMergesChangesFromParent = true
container.viewContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy
}
}
View:
import SwiftUI
import CoreData
import Intents
struct ContentView: View {
@Environment(\.managedObjectContext) private var viewContext
@State private var view: Bool = false
@FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Item.text, ascending: true)],
animation: .default)
private var items: FetchedResults<Item>
var body: some View {
NavigationView {
List {
ForEach(items) { item in
Text(item.text!)
}
.onDelete(perform: deleteItems)
}
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
EditButton()
}
ToolbarItem {
Button(action: addItem) {
Label("Add Item", systemImage: "plus")
}
}
}
}
}
private func addItem() {
withAnimation {
let newItem = Item(context: viewContext)
newItem.text = "\(Int.random(in: 0...1000))"
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)")
}
makeDonation(text: newItem.text!)
}
}
func makeDonation(text: String) {
let intent = MakeUppercaseIntent()
intent.text = text
intent.unit = "1"
intent.suggestedInvocationPhrase = "Add \(text) to app"
let interaction = INInteraction(intent: intent, response: nil)
interaction.donate { (error) in
if error != nil {
if let error = error as NSError? {
print("Donation failed: %@" + error.localizedDescription)
}
} else {
print("Successfully donated interaction")
}
}
}
private func deleteItems(offsets: IndexSet) {
withAnimation {
offsets.map { items[$0] }.forEach(viewContext.delete)
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)")
}
}
}
}
Hello
I have a function to add data to Core Data that has a completion and uses Futures, I wanted to know what is the best way to convert it to use async, because I just started learning how to use async and await. (I am not really sure how to do it)
Here is the function:
func add(context: NSManagedObjectContext, _ body: @escaping (inout Entity) -> Void) -> AnyPublisher<Entity, Error> {
Deferred { [context] in
Future { promise in
context.perform {
var entity = Entity(context: context)
body(&entity)
do {
try context.save()
promise(.success(entity))
} catch {
promise(.failure(error))
}
}
}
}
.eraseToAnyPublisher()
}
Thank You
Hello
I have a list of data in SwiftUI. The data shown in the list can be saved or deleted by using Core Data.
In the @FetchRequest property that I am using to display data, I initialized an NSPredicate and in the view, I gave the possibility to the user to change the value of the predicate so that he can filter data, and that is all working, the problem shows up when I delete data from the list when I do so the predicate becomes nil and I don't know why.
Here is the code
struct SectionList: View {
@FetchRequest(
entity: LifetimeInputs.entity(),
sortDescriptors: [NSSortDescriptor(keyPath: \LifetimeInputs.date, ascending: true)], predicate: nil
) var lifetimeInputsModel: FetchedResults<LifetimeInputs>
@FetchRequest(entity: Limit.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \Limit.date, ascending: false)]) var limit: FetchedResults<Limit>
@Environment(\.dynamicTypeSize) var dynamicTypeSize
var size: CGFloat{
if UIDevice.current.userInterfaceIdiom == .phone {
switch dynamicTypeSize {
case .xSmall: return 11
case .small: return 13
case .medium: return 15
case .large: return 17
case .xLarge: return 19
case .xxLarge: return 21
case .xxxLarge: return 23
default: return 23
}
} else {
switch dynamicTypeSize {
case .xSmall: return 13
case .small: return 15
case .medium: return 17
case .large: return 19
case .xLarge: return 21
case .xxLarge: return 23
case .xxxLarge: return 25
case .accessibility1: return 27
case .accessibility2: return 29
default: return 29
}
}
}
@StateObject var lifeTimeInputsViewModel = LifeTimeInputsViewModel()
@Environment(\.managedObjectContext) private var viewContext
var conversion: Double {
if !limit.isEmpty{
switch limit.last?.unita {
case Unit.ml.rawValue: return 1
case Unit.oz.rawValue: return 29.574
default: return 1
}
}
return 1
}
@State private var wantsToFilter: Bool = false
@State private var dateSelected = Date()
var body: some View {
Section{
HStack{
Text("Filter")
Spacer()
Image(systemName: wantsToFilter ? "checkmark.circle" : "xmark")
.font(.system(size: size + 6))
.foregroundColor(wantsToFilter ? .green : .red)
.onTapGesture {
wantsToFilter.toggle()
if wantsToFilter{
lifetimeInputsModel.nsPredicate = NSPredicate(
format: "date >= %@ && date <= %@",
Calendar.current.dateInterval(of: .day, for: dateSelected)!.start as CVarArg,
Calendar.current.dateInterval(of: .day, for: dateSelected)!.end as CVarArg
)
} else{
lifetimeInputsModel.nsPredicate = nil
}
}
}
DatePicker("Date", selection: $dateSelected, displayedComponents: .date)
} header: {
Text("Filter")
.font(.system(size: size - 4))
}
.onChange(of: dateSelected, perform: { _ in
if wantsToFilter{
lifetimeInputsModel.nsPredicate = NSPredicate(
format: "date >= %@ && date <= %@",
Calendar.current.dateInterval(of: .day, for: dateSelected)!.start as CVarArg,
Calendar.current.dateInterval(of: .day, for: dateSelected)!.end as CVarArg
)
}
})
Section{
ForEach(lifetimeInputsModel){ lifetimeInputs in
HStack{
Text("\(lifetimeInputs.valori / conversion, specifier: format(unita: !limit.isEmpty ? limit[limit.count - 1].unita ?? ml : ml)) \(!limit.isEmpty ? limit[limit.count - 1].unita ?? ml: ml)")
.font(.system(size: size))
Spacer()
Text("\(dateFormatter.string(from: lifetimeInputs.date ?? Date()))")
.font(.system(size: size))
}
}
.onDelete{lifeTimeInputsViewModel.deleteItems(offsets: $0, lifetimeInputsModel: lifetimeInputsModel); }
} header: {
Text("History \(lifetimeInputsModel.count)".localized()).font(.system(size: size - 4))
}
}
}
Thank You!
Hello
I have an app that uses Core Data with CloudKit to store data. When I am in the app (using the app) and create some new data on an other device, the data is fetched in a few seconds and I see it immediately, however if I am not using the app and create some new data on an other device, I have to enter the app and then the data starts fetching, is there a way to fetch data even if I am not using the app.
Here is my core data stack:
import CoreData
import Combine
class PersistenceController {
static let shared = PersistenceController()
let container: NSPersistentCloudKitContainer
init() {
container = NSPersistentCloudKitContainer(name: "CoreData")
guard let fileContainer = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "APP_GROUP_NAME")?.appendingPathComponent("CoreData.sqlite") else {
fatalError("Shared file container could not be created.")
}
let storeDescription = NSPersistentStoreDescription(url: fileContainer)
storeDescription.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
storeDescription.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
storeDescription.cloudKitContainerOptions = NSPersistentCloudKitContainerOptions(containerIdentifier: "Container_Identifier")
container.persistentStoreDescriptions = [storeDescription]
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
container.viewContext.automaticallyMergesChangesFromParent = true
container.viewContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy
}
}
Hello
I have this Core Data stack and I have an observer to observe NSPersistentStoreRemoteChange, I would like to filter changes that the user has made to call the mergePersistentHistoryChanges() just when needed, I think it has to be done in the fetchPersistentHistoryTransactionsAndChanges() function but I don't know how to do it. Can you help me. Thank You
Here is my Core Data Stack:
class PersistenceController {
static let shared = PersistenceController()
private var notificationToken: NSObjectProtocol?
init() {
notificationToken = NotificationCenter.default.addObserver(forName: .NSPersistentStoreRemoteChange, object: nil, queue: nil) { note in
Task {
await self.fetchPersistentHistory()
}
}
}
deinit {
if let observer = notificationToken {
NotificationCenter.default.removeObserver(observer)
}
}
private var lastToken: NSPersistentHistoryToken?
/// A persistent container to set up the Core Data stack.
lazy var container: NSPersistentCloudKitContainer = {
let fileContainer = URL.storeURL(for: "group name", databaseName: "CoreData")
let container = NSPersistentCloudKitContainer(name: "CoreData")
let defaultDirectoryURL = NSPersistentContainer.defaultDirectoryURL()
let localStoreURL = defaultDirectoryURL.appendingPathComponent("Local.sqlite")
let localStoreDescription = NSPersistentStoreDescription(url: localStoreURL)
localStoreDescription.configuration = "Local"
// Create a store description for a CloudKit-backed local store
let cloudStoreDescription = NSPersistentStoreDescription(url: fileContainer)
cloudStoreDescription.configuration = "Cloud"
// Set the container options on the cloud store
cloudStoreDescription.cloudKitContainerOptions = NSPersistentCloudKitContainerOptions(containerIdentifier: "containerIdentifier")
cloudStoreDescription.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
cloudStoreDescription.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
container.persistentStoreDescriptions = [cloudStoreDescription, localStoreDescription]
container.loadPersistentStores { storeDescription, error in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
}
// This sample refreshes UI by consuming store changes via persistent history tracking.
/// - Tag: viewContextMergeParentChanges
container.viewContext.automaticallyMergesChangesFromParent = false
container.viewContext.name = "viewContext"
container.viewContext.transactionAuthor = "User"
/// - Tag: viewContextMergePolicy
container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
container.viewContext.undoManager = nil
container.viewContext.shouldDeleteInaccessibleFaults = true
return container
}()
private func newTaskContext() -> NSManagedObjectContext {
// Create a private queue context.
/// - Tag: newBackgroundContext
let taskContext = container.newBackgroundContext()
taskContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
// Set unused undoManager to nil for macOS (it is nil by default on iOS)
// to reduce resource requirements.
taskContext.undoManager = nil
return taskContext
}
func save() {
if self.container.viewContext.hasChanges {
do {
try self.container.viewContext.save()
} catch {
print(Errors.errorSaving)
}
}
}
func fetchPersistentHistory() async {
do {
try await fetchPersistentHistoryTransactionsAndChanges()
} catch {
print(Errors.fetchPersistentHistory)
}
}
private func fetchPersistentHistoryTransactionsAndChanges() async throws {
let taskContext = newTaskContext()
taskContext.name = "persistentHistoryContext"
try await taskContext.perform {
let changeRequest = NSPersistentHistoryChangeRequest.fetchHistory(after: self.lastToken)
let historyResult = try taskContext.execute(changeRequest) as? NSPersistentHistoryResult
if let history = historyResult?.result as? [NSPersistentHistoryTransaction],
!history.isEmpty {
self.mergePersistentHistoryChanges(from: history)
return
}
throw Errors.fetchPersistentHistoryTransactionsAndChanges
}
}
private func mergePersistentHistoryChanges(from history: [NSPersistentHistoryTransaction]) {
let viewContext = container.viewContext
viewContext.perform {
for transaction in history {
print("Merged by func mergePersistentHistoryChanges ")
viewContext.mergeChanges(fromContextDidSave: transaction.objectIDNotification())
self.lastToken = transaction.token
}
}
}
}