对深度嵌套值使用绑定时,SwiftUI崩溃
我正在努力使我的应用程序内容与远程数据保持反应和最新。使用对深度嵌套值使用绑定时,SwiftUI崩溃,swiftui,swiftui-navigationlink,Swiftui,Swiftui Navigationlink,我正在努力使我的应用程序内容与远程数据保持反应和最新。使用导航链接探索我的值,但当我有2页深且原始项消失时,SwiftUI将崩溃 开始: class App: ObservableObject { @Published var items: [Item] = [ Item(id: "a", accounts: [ Account(id: "1"), Account(id: "2"), Account(
导航链接
探索我的值,但当我有2页深且原始项消失时,SwiftUI将崩溃
开始:
class App: ObservableObject {
@Published var items: [Item] = [
Item(id: "a", accounts: [
Account(id: "1"),
Account(id: "2"),
Account(id: "3")
])
]
}
但是,如果我在AccountView页面上,并且项目变为空,则应用程序将崩溃并出现“致命错误:索引超出范围”
我最初没有使用绑定,但是当帐户结构的内容更改时,AccountView没有更新,视图没有更改。现在,通过传递绑定,视图确实会正确更新,但如果列表大小发生变化,则可能会导致崩溃。是的,如果在代码的另一部分中项目变为空,则应用程序将崩溃。
在并发/多线程/异步等方面。。。你得自己照顾它。例如,使用GCD框架或Combine functional Responsive library来获得正在发生的事情的通知并对其采取行动。以下测试代码显示了一种可能的解决方法,以防止项目变为空时崩溃
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 = []
}
}
}
类项目{
let id:String
var账户:[账户]
初始化(id:字符串,帐户:[帐户]){
self.id=id
self.accounts=帐户
}
}
结构帐户{
let id:String
}
类应用程序:ObserveObject{
@已发布的var项目:[项目]=[
项目(id:“项目a”),账户:[
账户(id:“账户1”),
账户(id:“账户2”),
账户(id:“账户3”)
])
]
}
结构项目视图:视图{
@环境对象变量app:app
@状态变量itemNdx:Int
var body:一些观点{
itemNdx
看起来很不幸,但我不确定“看起来很不幸”是什么意思。这段代码有效,并提供了解决问题的方法。你试过了吗?我知道这有点挑剔,但我不喜欢只起作用的代码。我宁愿选择一个有意义且似乎合适的解决方案。我发现了一些其他的选项,它们有一些优点和缺点,但是这个解决方案看起来非常复杂,仅仅显示一个列表就可以了。我对你找到的解决方案很感兴趣。让我们知道。我想出了另一个解决问题的方法:你可以考虑方法——原因与你的崩溃有相同的根源,在那种情况下。你能给出一个起点/代码吗?
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)
}
}
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 = []
}
}
}