swiftui - 使用深度嵌套值的绑定时 SwiftUI 崩溃
问题描述
我正在尝试使我的应用程序内容保持反应性并与远程数据保持同步。我的价值观是使用 a 来探索的NavigationLink
,但是当我深入 2 页并且原始项目消失时,SwiftUI 会崩溃。
开始:
class App: ObservableObject {
@Published var items: [Item] = [
Item(id: "a", accounts: [
Account(id: "1"),
Account(id: "2"),
Account(id: "3")
])
]
}
struct AllItems: View {
@EnvironmentObject var app: App
var body: some View {
ForEach(app.items.indices, id: \.self) { index in
NavigationLink(destination: ItemView(item: self.$app.items[index])) {
Text(self.app.items[index].id)
}
}
}
}
struct ItemView: View {
@Binding var item: Item
var body: some View {
ForEach(item.accounts.indices, id: \.self) { index in
NavigationLink(destination: AccountView(item: self.$item.accounts[index])) {
Text(self.item.accounts[index].id)
}
}
}
}
struct AccountView: View {
@Binding var account: Account
var body: some View {
Text(account.id)
}
}
但是,如果我在 AccountView 页面上并items
变为空,则应用程序将因“致命错误:索引超出范围”而崩溃。
我最初没有使用绑定,但是当 Account 结构的内容发生更改时,AccountView 没有更新,视图没有更改。现在通过传递绑定,视图确实会正确更新,但如果列表大小发生变化,它可能会导致崩溃。
解决方案
以下测试代码显示了一种可能的解决方法,以防止在项目变空时崩溃。
class Item {
let id: String
var accounts: [Account]
init(id: String, accounts: [Account]) {
self.id = id
self.accounts = accounts
}
}
struct Account {
let id: String
}
class App: ObservableObject {
@Published var items: [Item] = [
Item(id: "item a", accounts: [
Account(id: "account 1"),
Account(id: "account 2"),
Account(id: "account 3")
])
]
}
struct ItemView: View {
@EnvironmentObject var app: App
@State var itemNdx: Int
var body: some View {
itemNdx < self.app.items.count
? AnyView(ForEach(app.items[itemNdx].accounts.indices, id: \.self) { index in
NavigationLink(destination: AccountView(itemNdx: self.itemNdx, accountNdx: index)) {
Text(self.app.items[self.itemNdx].accounts[index].id)
}
})
: AnyView(EmptyView())
}
}
struct AccountView: View {
@EnvironmentObject var app: App
@State var itemNdx: Int
@State var accountNdx: Int
var body: some View {
itemNdx < self.app.items.count
? AnyView(Text(app.items[itemNdx].accounts[accountNdx].id))
: AnyView(EmptyView())
}
}
struct AllItems: View {
@EnvironmentObject var app: App
var body: some View {
ForEach(app.items.indices, id: \.self) { index in
NavigationLink(destination: ItemView(itemNdx: index)) {
Text(self.app.items[index].id)
}
}
}
}
struct ContentView: View {
// the app is passed in from the SceneDelegate "var app = App()"
@EnvironmentObject var app: App
var body: some View {
NavigationView {
AllItems()
}.navigationViewStyle(StackNavigationViewStyle())
.onAppear(perform: loadData)
}
func loadData() {
// this will set the items to empty in 10 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + 10) {
self.app.items = []
}
}
}
推荐阅读
- python - 如何在 python beautifulsoup 中从 html 中找到第二个 div
- laravel - 使用 apiResource 时找不到页面
- javascript - 如何在javascript中有条件地返回正则表达式匹配?
- sql - 如何根据另一个表中的日期范围获取记录
- fullcalendar - Fullcalendar 自定义视图点击事件
- java - 我应该在哪里运行自定义 SQL 以在 Spring Boot 中的数据库中创建枚举类型?
- node.js - Heroku 上的 PayloadTooLargeError,但仅在使用移动设备时
- python - Tkinter:在 GUI 中跳过 PDF
- javascript - 抓取网页数据
- sorting - 给定要在 O(n) 中解决的问题,但接受使用 sort() 的解决方案