[英]How to retrieve and show data on screen in SwiftUI?
我將簡單數據存儲在我想要檢索並在屏幕上顯示的核心數據中,但我不確定我應該如何以及在哪里編寫該代碼以在屏幕上顯示它,因為我總是出現超出范圍的錯誤..
此外,並非所有數據都在時間保存,只有當我滾動到底部時才保存
import SwiftUI
import CoreData
struct ContentView: View {
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Item.title, ascending: true)],
animation: .default)
private var items: FetchedResults<Item>
@StateObject private var viewModel = HomeViewModel()
var body: some View {
GeometryReader { geometry in
NavigationView {
ScrollView {
LazyVGrid(columns: Array(repeating: .init(.flexible()),
count: UIDevice.current.userInterfaceIdiom == .pad ? 4 : 2)) {
ForEach(viewModel.results, id: \.self) {
let viewModel = ResultVM(model: $0)
NavigationLink(destination: {
DetailView(data: viewModel.trackName)
}, label: {
SearchResultRow(resultVM: viewModel, coreDM: PersistenceController())
})
}
}
}
}
.onAppear(perform: {
viewModel.performSearch()
})
}
}
}
struct SearchResultRow: View {
let resultVM: ResultVM
let coreDM: PersistenceController
var body: some View {
HStack {
RoundedRectangle(cornerRadius: 16).fill(.yellow)
.frame(maxWidth: .infinity).aspectRatio(1, contentMode: .fit)
.overlay(Text(resultVM.trackName)) // want to show data from Core data here
}.padding()
.background(Color.red)
.onAppear(perform: {
coreDM.saveResult(title: resultVM.trackName)
})
}
}
來自 API 的數據顯示哪些相同的數據存儲在 CoreData
保存和檢索的方法(工作正常)
func saveResult(title: String) {
let result = Item(context: container.viewContext)
result.title = title
do {
try container.viewContext.save()
}
catch {
print("error")
}
}
func getResult() -> [Item] {
let fetchRequest: NSFetchRequest<Item> = Item.fetchRequest()
do {
return try container.viewContext.fetch(fetchRequest)
}
catch {
return []
}
}
API 調用
import Foundation
import CoreData
class HomeViewModel: ObservableObject {
@Published var results = [ResultItem]()
func performSearch() {
guard let gUrl = URL(
string: "https://api.artic.edu/api/v1/artworks"
) else { return }
Task {
do {
let (data, _) = try await URLSession.shared.data(from: gUrl)
let response = try JSONDecoder()
.decode(ResponseData.self, from: data)
DispatchQueue.main.async { [weak self] in
self?.results = response.data ?? []
}
} catch {
print("*** ERROR ***")
}
}
}
}
刪除我們在 SwiftUI 中不使用視圖模型對象的視圖模型。 View
結構存儲視圖數據並進行依賴跟蹤,屬性包裝器為其提供外部更改跟蹤功能,如對象。 如果您在頂部添加一個實際對象,您將獲得 SwiftUI 旨在消除的一致性錯誤。 所以首先刪除這個:
@StateObject private var viewModel = HomeViewModel()
您已經有了獲取請求屬性包裝器,正如我所說,它提供了View
更改跟蹤,因此當items
更改(例如,添加、刪除或移動項目)時,將調用body
,因此只需在ForEach
中使用它即可這個:
ForEach(items) { item in
NavigationLink(destination: {
DetailView(item: item)
}, label: {
SearchResultRow(item: item)
})
}
然后在您的子視圖中使用@ObservedObject
,這使View
能夠跟蹤項目的更改,因此當項目的屬性發生更改時將調用 body,例如item.title
。 在DetailView
中執行相同的操作。
struct SearchResultRow: View {
@ObservedObject var item: Item
在我看來,您正在嘗試在 Core Data 中下載和緩存數據。 這是不必要的,因為您可以簡單地在 NSURLSession 上設置一個 NSURLCache ,它會自動為您緩存它,即使離線也可以工作。 但是,如果你真的想自己在 Core Data 中緩存它,那么架構應該是你的 UI 從 Core Data 中獲取它,然后你有另一個對象負責將遠程數據同步到 Core Data 中。 通常這將在App
結構級別而不是在出現的視圖中。 當數據保存到核心數據時,托管對象上下文上下文將被更改, @FetchRequest
正在偵聽並調用body
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.