调用ObservableObject类初始化器来更新SwiftUI中的List



我有一个列表,更新了一个Fetch类,一个ObservableObject。它有一个init函数。这就是那个Fetch类。


@Published private(set) var items: [ItemsResult] = []

init() {
let url = URL(string: "[redacted]")!

URLSession.shared.dataTask(with: url) {(data, response, error) in
do {
if let itemsData = data {
let decodedData = try JSONDecoder().decode([ItemsResult].self, from: itemsData)
DispatchQueue.global(qos: .utility).async {
DispatchQueue.main.async {
print("running task")
self.items = decodedData
}
}

print(self.items)
} else {
print("No data")
}
} catch {
print("Error: (error)")
}
}.resume()
}

构建应用程序时,它正确显示API返回的数据,并且与数据库匹配。但是,当我点击其中一个以删除它,或者使用我添加的文本区域添加新项目时,它不会更新。

struct TickrApp: View {
@EnvironmentObject var fetch: Fetch
var body: some View {
NavigationView {
Form {
Section {
VStack(alignment: .center) {
Text("Welcome to Tickr")
}
}
Section {
List(fetch.items) { item in
CheckView(checked: item.done, title: item.content.replacingOccurrences(of:"_", with: " "))
}
}
AddItemView()
}.navigationBarTitle(Text("Tickr"))
}
}
}

数据库正在更新,如我记录它们响应的decodedData时所示,但是在每个中我只调用Fetch()。在所有三种情况下,请求都是相同的。

一个调用,用于文本输入。

func toggle() {
checked = !checked
let url = URL(string: "")!
var req = URLRequest(url: url)
req.httpMethod = "POST"

let task = URLSession.shared.dataTask(with: req) { data, response, error in
guard let _ = data,
let response = response as? HTTPURLResponse,
error == nil else {
print("error", error ?? "Unknown error")
return
}

guard (200 ... 299) ~= response.statusCode else {
print("statusCode should be 2xx, but is (response.statusCode)")
print("response = (response)")
return
}
}
task.resume()
Fetch()

为了在视觉上更新列表,我需要完全退出应用程序/重新运行它,以便正确显示新的和/或删除的项目。没有显示后台发布更改或其他任何错误。

您似乎正在尝试调用Fetch()来刷新您的数据。这里有两个问题:

  1. 你在dataTask完成处理程序的之外调用它。这意味着它可能在写操作完成之前被调用

  2. 调用Fetch()只是创建一个新的Fetch实例,当你真正想做的是更新你现有实例的结果。

假设你的第一个代码剪辑是从Fetch。我想把它改成这样:

class Fetch: ObservableObject {
@Published private(set) var items: [ItemsResult] = []
init() {
performFetch()
}
func performFetch() {
//your existing fetch code that was in `init`
}
}

然后,在AddItemViewCheckView中,确保有这样一行:

@EnvironmentObject var fetch: Fetch
这将确保您使用Fetch相同的实例,因此您的列表将反映相同的结果集合。

一旦你完成了像toggle()这样的操作,调用self.fetch.performFetch()来更新结果。所以,你的最后一个代码片段会变成这样:

let task = URLSession.shared.dataTask(with: req) { data, response, error in 
//guard statements to check for errors
self.fetch.performFetch() //perform your refresh on the *existing* `Fetch` instance
}

更大的重构将涉及将您的异步代码(如toggle)移动到视图模型中,而不是在View代码中执行任何。此外,看看使用URLSession出版商使用组合,因为你正在使用SwiftUI: https://developer.apple.com/documentation/foundation/urlsession/processing_url_session_data_task_results_with_combine

最新更新