CoreData Werte für LineChartView verwenden

    Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

    • CoreData Werte für LineChartView verwenden

      Hallo,

      ich bin am Anfang mit Swift und CoreData und habe dazu einige Tutorials gelesen und im Prinzip kann ich Daten speichern und diese in einem View ausgeben.
      Nun stehe ich vor der Herausforderung die Daten die im CoreData gespeichert sind als Werte in Arrays zu speichern um diese dann z.B. als Input für ein LineChart zu nutzen.

      Es hat sich für mich erst einmal einfach angehört, aber wie häufig komme ich da aktuell nicht weiter und benötige einen Denkanstoß :)

      Ich habe die folgende Funktion:

      Quellcode

      1. private func fetchItem() {
      2. withAnimation {
      3. let fetchRequest: NSFetchRequest<Item> = Item.fetchRequest()
      4. do {
      5. let fetchedResults = try viewContext.fetch(fetchRequest)
      6. print("#Entities: \(fetchedResults.count)")
      7. } catch {
      8. print(error)
      9. }
      10. }
      11. }
      Alles anzeigen

      Ich habe die Funktion bei .onAppear

      Quellcode

      1. .onAppear(perform: {
      2. print("View loaded")
      3. fetchItem()
      4. })

      der ContentView aufgerufen und bekomme dann auch das erwartete Ergebnis:

      Quellcode

      1. View loaded
      2. #Entities: 10
      Da ich bei SwiftUI nichts gefunden habe bin ich auf Github auf das Projekt SwiftUICharts gestoßen.
      Dort werden die Daten für den Line Chart folgendermaßen bereitgestellt - hier ein Beispiel aus dem Projekt:

      Quellcode

      1. private static func weekOfData() -> LineChartData {
      2. let data = LineDataSet(dataPoints: [
      3. LineChartDataPoint(value: 12000, xAxisLabel: "M", description: "Monday"),
      4. LineChartDataPoint(value: 10000, xAxisLabel: "T", description: "Tuesday"),
      5. LineChartDataPoint(value: 8000, xAxisLabel: "W", description: "Wednesday"),
      6. LineChartDataPoint(value: 17500, xAxisLabel: "T", description: "Thursday"),
      7. LineChartDataPoint(value: 16000, xAxisLabel: "F", description: "Friday"),
      8. LineChartDataPoint(value: 11000, xAxisLabel: "S", description: "Saturday"),
      9. LineChartDataPoint(value: 9000, xAxisLabel: "S", description: "Sunday")
      10. ],
      11. ...
      12. ...
      Alles anzeigen
      Bei mir wären es aus dem CoreData Model dann Datum mit einem zugehörigen Double Wert. Das Datum wäre dann das xAxisLabel mit dem Double Wert als Value.

      Jetzt habe ich keine Idee mehr wie ich aus den NSManagedObject Einträgen der CoreData Database nun die LineChartDataPoint "befülle".

      Meine erste Idee wäre hier das ich zwei Arrays aus den Daten erzeuge -> Dates[]: String und Values[]: Double.
      Mir ist aber nicht klar wie ich das bewerkstelligen könnte??

      Vielleicht bin ich auch komplett auf dem Holzweg was meinen Lösungsansatz betrifft ?(

      Ich hoffe Ihr könnt mir mal wieder ein paar Denkanstöße geben :)

      Gruß

      Ralf
    • Ich habe das mal in ein kleines Projekt gegossen um Euch vielleicht/hoffentlich einen besseren Einblick zu geben. Hier mal der Code zu dem Projekt (die wichtigsten Files)

      Quellcode: LineChartDemoApp.swift

      1. import SwiftUI
      2. @main
      3. struct LineChartDemoApp: App {
      4. let persistenceController = PersistenceController.shared
      5. var body: some Scene {
      6. WindowGroup {
      7. ContentView()
      8. .environment(\.managedObjectContext, persistenceController.container.viewContext)
      9. }
      10. }
      11. }
      Alles anzeigen

      Quellcode: ContentView.swift

      1. import SwiftUI
      2. import CoreData
      3. struct ContentView: View {
      4. @Environment(\.managedObjectContext) private var viewContext
      5. @FetchRequest(
      6. sortDescriptors: [NSSortDescriptor(keyPath: \Rate.date, ascending: true)],
      7. animation: .default)
      8. private var items: FetchedResults<Rate>
      9. var body: some View {
      10. NavigationView {
      11. List {
      12. ForEach(items) { item in
      13. Text("Date: \(item.date!) Value: \(item.value)")
      14. }
      15. .onDelete(perform: deleteItems)
      16. }
      17. .toolbar {
      18. #if os(iOS)
      19. ToolbarItem {
      20. EditButton()
      21. }
      22. #endif
      23. ToolbarItem(placement: .bottomBar) {
      24. Button(action: addItem) {
      25. Label("Add Item", systemImage: "plus")
      26. }
      27. }
      28. }
      29. }
      30. }
      31. private func fetchItem() {
      32. withAnimation {
      33. let fetchRequest: NSFetchRequest<Rate> = Rate.fetchRequest()
      34. do {
      35. let fetchedResults = try viewContext.fetch(fetchRequest)
      36. print("#Entities: \(fetchedResults.count)")
      37. } catch {
      38. print(error)
      39. }
      40. }
      41. }
      42. private func addItem() {
      43. withAnimation {
      44. let newItem = Rate(context: viewContext)
      45. newItem.date = Date()
      46. newItem.value = randomDouble()
      47. do {
      48. try viewContext.save()
      49. } catch {
      50. // Replace this implementation with code to handle the error appropriately.
      51. // 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.
      52. let nsError = error as NSError
      53. fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
      54. }
      55. }
      56. }
      57. private func deleteItems(offsets: IndexSet) {
      58. withAnimation {
      59. offsets.map { items[$0] }.forEach(viewContext.delete)
      60. do {
      61. try viewContext.save()
      62. } catch {
      63. // Replace this implementation with code to handle the error appropriately.
      64. // 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.
      65. let nsError = error as NSError
      66. fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
      67. }
      68. }
      69. }
      70. }
      71. private let itemFormatter: DateFormatter = {
      72. let formatter = DateFormatter()
      73. formatter.dateStyle = .short
      74. formatter.timeStyle = .medium
      75. return formatter
      76. }()
      77. struct ContentView_Previews: PreviewProvider {
      78. static var previews: some View {
      79. ContentView().environment(\.managedObjectContext, PersistenceController.preview.container.viewContext)
      80. }
      81. }
      Alles anzeigen

      Quellcode: Persistence.swift

      1. import CoreData
      2. struct PersistenceController {
      3. static let shared = PersistenceController()
      4. static var preview: PersistenceController = {
      5. let result = PersistenceController(inMemory: true)
      6. let viewContext = result.container.viewContext
      7. /*
      8. for _ in 0..<10 {
      9. let newItem = Rate(context: viewContext)
      10. newItem.date = Date()
      11. newItem.value = randomDouble()
      12. }
      13. */
      14. do {
      15. try viewContext.save()
      16. } catch {
      17. // Replace this implementation with code to handle the error appropriately.
      18. // 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.
      19. let nsError = error as NSError
      20. fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
      21. }
      22. return result
      23. }()
      24. let container: NSPersistentContainer
      25. init(inMemory: Bool = false) {
      26. container = NSPersistentContainer(name: "DataModel")
      27. if inMemory {
      28. container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
      29. }
      30. container.loadPersistentStores(completionHandler: { (storeDescription, error) in
      31. if let error = error as NSError? {
      32. // Replace this implementation with code to handle the error appropriately.
      33. // 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.
      34. /*
      35. Typical reasons for an error here include:
      36. * The parent directory does not exist, cannot be created, or disallows writing.
      37. * The persistent store is not accessible, due to permissions or data protection when the device is locked.
      38. * The device is out of space.
      39. * The store could not be migrated to the current model version.
      40. Check the error message to determine what the actual problem was.
      41. */
      42. fatalError("Unresolved error \(error), \(error.userInfo)")
      43. }
      44. })
      45. }
      46. }
      47. func randomDouble() -> Double {
      48. let number = Double.random(in: -100...100)
      49. return number
      50. }
      Alles anzeigen

      Quellcode: Rate+CoreDataProperties.swift

      1. import Foundation
      2. import CoreData
      3. extension Rate {
      4. @nonobjc public class func fetchRequest() -> NSFetchRequest<Rate> {
      5. return NSFetchRequest<Rate>(entityName: "Rate")
      6. }
      7. @NSManaged public var date: Date?
      8. @NSManaged public var value: Double
      9. }
      10. extension Rate : Identifiable {
      11. }
      Alles anzeigen
    • Hallo zusammen,

      ich habe die Antwort bekommen, das Schlüsselwort ist "map".
      Hier der Code den ich in die fetchItem() Methode eingebaut habe:

      Quellcode

      1. @State var data: [Double] = []
      2. ...
      3. ...
      4. var body: some View {
      5. ZStack {
      6. iLineChart(
      7. data: self.data,
      8. ...
      9. ...
      10. private func fetchItem() {
      11. withAnimation {
      12. let fetchRequest: NSFetchRequest<Rate> = Rate.fetchRequest()
      13. do {
      14. let fetchedResults = try viewContext.fetch(fetchRequest)
      15. //let data = fetchedResults.map { $0.value }
      16. for aRate in fetchedResults {
      17. data.append(aRate.value)
      18. }
      19. print("#Entities: \(fetchedResults.count)")
      20. for element in data {
      21. print("Value: \(element)")
      22. }
      23. } catch {
      24. print(error)
      25. }
      26. }
      27. }
      Alles anzeigen
      Gruß

      Ralf