在 swiftUI 中定期更新列表
Periodically update list in swiftUI
我正在尝试构建一个从服务器加载列表并每 x
秒更新每个列表项视图的 macOS 应用程序。
我浏览了一些现有代码并遵循了一些教程,因为我仍在学习,但我似乎无法弄清楚出了什么问题。
我有一个 Store
保存数据并像这样定期更新它:
class Store: NSObject, ObservableObject {
@Published var items: [Item]
var timer: Timer = Timer()
override init() {
var newItems: [Item] = []
// updateList calls the web service and receives a `[Item]`
updateList(update: { i in
newItems = i
})
items = newItems
super.init()
startTimer()
}
func startTimer() {
self.timer = Timer.scheduledTimer(withTimeInterval: 5, repeats: true, block: { _ in
var newList: [Item] = []
updateList(update: { vals in
newList = vals
})
self.objectWillChange.send()
items = newList
})
}
}
视图如下所示:
struct ContentView: View {
@ObservedObject var store: Store
var body: some View {
VStack(alignment: .leading, spacing: 12) {
List(store.items, id: \.self) { item in
ListRow(item: binding(for: item))
}
}
.frame(minWidth: windowSize().minWidth, minHeight: windowSize().minHeight)
.navigationTitle("Mission")
.toolbar {
ToolbarItem(placement: .status) {
Button(action: { /* Show connect dialog */ }) {
Image(systemName: "network")
}
}
ToolbarItem(placement: .primaryAction) {
Button(action: { /* Show file chooser/magnet entry dialog */ }) {
Image(systemName: "plus")
}
}
}
}
func binding(for item: Item) -> Binding<Item> {
guard let index = store.items.firstIndex(where: { [=11=].id == item.id }) else {
fatalError("Can't find in array")
}
return $store.items[index]
}
}
struct ListRow: View {
@Binding var item: Item
var body: some View {
Text(item.name)
.padding(.all, 20)
}
}
当我 运行 应用程序时,它是一个空列表。我可以添加断点,我可以看到项目列表正在正确发送,所以我觉得列表视图本身做错了什么,但我不确定。我唯一确定的是我的 updateList
方法 100% 返回 Item
的列表。有什么想法吗?
尽管您没有显示足够的代码来重现您的问题,尤其是 updateList
所做的,请尝试这样的事情(未经测试的代码):
class Store: NSObject, ObservableObject {
@Published var items: [Item] = [] // <-- here
var timer: Timer = Timer()
override init() {
super.init()
// updateList calls the web service and receives a `[Item]`
updateList(update: { vals in // <-- here
self.items = vals // <-- here
})
startTimer()
}
func startTimer() {
self.timer = Timer.scheduledTimer(withTimeInterval: 5, repeats: true, block: { _ in
self.updateList(update: { vals in // <-- here
self.objectWillChange.send() // <-- here
self.items = vals // <-- here
})
})
}
}
你还必须在 ContentView
之前有类似的东西,
@StateObject var store = Store()
你传递为 ContentView(store: store)
.
我正在尝试构建一个从服务器加载列表并每 x
秒更新每个列表项视图的 macOS 应用程序。
我浏览了一些现有代码并遵循了一些教程,因为我仍在学习,但我似乎无法弄清楚出了什么问题。
我有一个 Store
保存数据并像这样定期更新它:
class Store: NSObject, ObservableObject {
@Published var items: [Item]
var timer: Timer = Timer()
override init() {
var newItems: [Item] = []
// updateList calls the web service and receives a `[Item]`
updateList(update: { i in
newItems = i
})
items = newItems
super.init()
startTimer()
}
func startTimer() {
self.timer = Timer.scheduledTimer(withTimeInterval: 5, repeats: true, block: { _ in
var newList: [Item] = []
updateList(update: { vals in
newList = vals
})
self.objectWillChange.send()
items = newList
})
}
}
视图如下所示:
struct ContentView: View {
@ObservedObject var store: Store
var body: some View {
VStack(alignment: .leading, spacing: 12) {
List(store.items, id: \.self) { item in
ListRow(item: binding(for: item))
}
}
.frame(minWidth: windowSize().minWidth, minHeight: windowSize().minHeight)
.navigationTitle("Mission")
.toolbar {
ToolbarItem(placement: .status) {
Button(action: { /* Show connect dialog */ }) {
Image(systemName: "network")
}
}
ToolbarItem(placement: .primaryAction) {
Button(action: { /* Show file chooser/magnet entry dialog */ }) {
Image(systemName: "plus")
}
}
}
}
func binding(for item: Item) -> Binding<Item> {
guard let index = store.items.firstIndex(where: { [=11=].id == item.id }) else {
fatalError("Can't find in array")
}
return $store.items[index]
}
}
struct ListRow: View {
@Binding var item: Item
var body: some View {
Text(item.name)
.padding(.all, 20)
}
}
当我 运行 应用程序时,它是一个空列表。我可以添加断点,我可以看到项目列表正在正确发送,所以我觉得列表视图本身做错了什么,但我不确定。我唯一确定的是我的 updateList
方法 100% 返回 Item
的列表。有什么想法吗?
尽管您没有显示足够的代码来重现您的问题,尤其是 updateList
所做的,请尝试这样的事情(未经测试的代码):
class Store: NSObject, ObservableObject {
@Published var items: [Item] = [] // <-- here
var timer: Timer = Timer()
override init() {
super.init()
// updateList calls the web service and receives a `[Item]`
updateList(update: { vals in // <-- here
self.items = vals // <-- here
})
startTimer()
}
func startTimer() {
self.timer = Timer.scheduledTimer(withTimeInterval: 5, repeats: true, block: { _ in
self.updateList(update: { vals in // <-- here
self.objectWillChange.send() // <-- here
self.items = vals // <-- here
})
})
}
}
你还必须在 ContentView
之前有类似的东西,
@StateObject var store = Store()
你传递为 ContentView(store: store)
.