Swift UI无法从核心数据中获取数据

li9yvcax  于 2023-02-07  发布在  Swift
关注(0)|答案(1)|浏览(175)

我尝试使用Swift UI从核心数据中保存和获取数据。我调试代码,可以看到数据保存到核心数据中,并且有5条记录,但问题是当我尝试重新加载并重新运行它时,它只显示一条记录。
下面是代码视图模型。

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)
        }

    }
}

下面是主应用程序的代码。

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)
        }
    }
}

下面是进入内容视图的代码。

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)    }
}

下面是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()
                }
            }

        }
    }
}

下面是标题的代码.swift ..

import SwiftUI

struct HeadTitleView: View {

    @EnvironmentObject var viewModel: RedditViewModel
    let title: String

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

下面是截图。

yzuktlbb

yzuktlbb1#

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

在这里,您创建了一个实体对象,但随后在循环中重用了同一个对象,因此最终要做的是用每个故事更新这个对象,而不是为每个故事创建一个新对象。
只需交换线路即可解决问题

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

相关问题