Home > OS >  Swift UI unable to fetch data form Core Data
Swift UI unable to fetch data form Core Data

Time:02-04

I am trying to save and fetch data form core data by using swift UI . I debug the code , I can see the the data is saved into core data and it has 5 record but the problem is when I tried to reload and re-run it it showing only one record.

Here is the code View Model ..

import Foundation
import CoreData

@MainActor
class RedditViewModel: ObservableObject {

    @Published private(set) var stories = [Story]()


    private var redditService: RedditService

    init(redditService: RedditService = RedditService()) {
        self.redditService = redditService
    }

    // Swift 5.5
    func fetchData(viewContext: NSManagedObjectContext) async {
        let url = NetworkURLs.urlBase
        do {
            let response = try await redditService.getModel(from: url)
            let stories = response.data.children.map { $0.data }
            self.stories = stories
            saveRecord(viewContext: viewContext)

        } catch (let error) {
            print(error)
        }
    }
    public func saveRecord(viewContext: NSManagedObjectContext) {

        do {
            let redit = ReditEntity(context: viewContext)
            stories.forEach { story in
                redit.title = story.title
                redit.numComments = Int64(story.numComments)
                redit.score = Int64(story.score)
                redit.urlImage = story.thumbnail

            }
            try viewContext.save()
        } catch {
            print(error.localizedDescription)
        }

    }
}

Here is the code for main app ..

import SwiftUI

@main
struct CoreDataDemoApp: App {

   @StateObject private var viewModel = RedditViewModel()
   let persistentContainer = CoreDataManager.shared.persistentContainer

    var body: some Scene {
        WindowGroup {
            ContentView().environment(\.managedObjectContext, persistentContainer.viewContext).environmentObject(viewModel)
        }
    }
}

Here is code into content view ..

import SwiftUI
import CoreData

struct ContentView: View {

    @EnvironmentObject private var viewModel: RedditViewModel
    @Environment(\.managedObjectContext) private var viewContext

    @FetchRequest(entity: ReditEntity.entity(), sortDescriptors: [])
    private var dbStories: FetchedResults<ReditEntity>
    var dbFatchReditRecord: NSFetchRequest<ReditEntity> = ReditEntity.fetchRequest()


    var body: some View {

        VStack {
            Text("Reddit Service")
                .font(.largeTitle)
            List {
                ForEach(dbStories) { story in
                    // custom cell
                    RowView(title: story.title ?? "", comments: "\(story.numComments)", score: "\(story.score)", urlImage: story.urlImage)
                }
            }
        }
        .onAppear {
            if dbStories.isEmpty {

                Task {
                    await viewModel.fetchData(viewContext: viewContext)

                }
            }
        }

    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        let persistedContainer = CoreDataManager.shared.persistentContainer
        ContentView().environment(\.managedObjectContext, persistedContainer.viewContext)    }
}

Here is the code for RowView.swift

import SwiftUI

struct RowView: View {

    @EnvironmentObject var viewModel: RedditViewModel

    let title: String
    let comments: String
    let score: String
    let urlImage: String?

    var body: some View {
        VStack(alignment: .leading) {
            HStack {
                if let urlImage = urlImage, urlImage.contains("https"), let url = URL(string: urlImage) {
                    AsyncImage(url: url)
                }
                VStack(alignment: .leading) {
                    HeadTitleView(title: title)
                    Text("Comments: \(comments)")
                    Text("Score: \(score)")
                    Spacer()
                }
            }

        }
    }
}

Here is the code for Header.swift ..

import SwiftUI

struct HeadTitleView: View {

    @EnvironmentObject var viewModel: RedditViewModel
    let title: String

    var body: some View {
        Text(title)
    }
}

Here is the screenshot ..

enter image description here

CodePudding user response:

let redit = ReditEntity(context: viewContext)
stories.forEach { story in
    redit.title = story.title
    ...
}

Here you are creating an entity object but then you reuse that same object inside the loop so what you end up doing is updating this single object with each story instead of creating a new object for each story.

Simply swap the lines to fix the problem

stories.forEach { story in
    let redit = ReditEntity(context: viewContext)
    redit.title = story.title
    ...
}
  • Related