如何使用 SwiftUI 从 TabView 内的 ForEach 中删除项目?
How can I remove an item from a ForEach inside of a TabView using SwiftUI?
我遇到了一个我无法理解的奇怪的 SwiftUI 崩溃。我有一个 TabView,其中包含 3 张图像的列表。我试图通过点击屏幕上的按钮从列表中删除第一张图片,但我遇到了崩溃。
'NSInternalInconsistencyException', reason: 'attempt to delete and reload the same index path (<NSIndexPath: 0x968bfe135e5a98d1> {length = 2, path = 0 - 0})'
terminating with uncaught exception of type NSException
如果我从代码中删除 TabView,它会按预期工作并删除第一项。这是重现此崩溃所需的最少代码量。我还在此处创建了此代码的 Git 存储库 -> https://github.com/cameronhenige/TestCrash 有人可以帮我弄清楚发生了什么吗?
import SwiftUI
struct ContentView: View {
@StateObject var testViewModel = TestViewModel()
var body: some View {
GeometryReader { proxy in
ScrollView {
VStack(alignment: .leading, spacing:0) {
TabView {
ForEach(testViewModel.images, id: \.self) { image in
Image(image)
}
}.tabViewStyle(PageTabViewStyle())
.clipShape(RoundedRectangle(cornerRadius: 15))
.padding()
.frame(width: proxy.size.width, height: proxy.size.height/2.5)
}
Button(action: {
testViewModel.removeFirst()
}) {
Text("Remove first item from list")
}
}
}.frame(maxWidth: .infinity).background(Color.black)
}
}
import Foundation
class TestViewModel: NSObject, ObservableObject {
@Published var images: [String] = ["dog", "cat", "bird"]
func removeFirst() {
images.remove(at: 0)
}
}
TabView {
ForEach(testViewModel.images, id: \.self) { image in
Image(image)
}
}.tabViewStyle(PageTabViewStyle())
.clipShape(RoundedRectangle(cornerRadius: 15))
.padding()
.frame(width: proxy.size.width, height: proxy.size.height/2.5)
.id(testViewModel.images.count)
向 TabView 添加 id 可以解决此问题!
有关为什么使用 .id(_:)
可以为您解决问题的更多解释,这是因为当 testViewModel.images.count
更改时(也就是视图现在使用不同的数据),您正在使视图无效,因为ID已更改。
有关使视图无效以及如何修复奇怪的视图更新的更多信息,请参阅 Demystify SwiftUI - WWDC21 演讲。
我遇到了一个我无法理解的奇怪的 SwiftUI 崩溃。我有一个 TabView,其中包含 3 张图像的列表。我试图通过点击屏幕上的按钮从列表中删除第一张图片,但我遇到了崩溃。
'NSInternalInconsistencyException', reason: 'attempt to delete and reload the same index path (<NSIndexPath: 0x968bfe135e5a98d1> {length = 2, path = 0 - 0})' terminating with uncaught exception of type NSException
如果我从代码中删除 TabView,它会按预期工作并删除第一项。这是重现此崩溃所需的最少代码量。我还在此处创建了此代码的 Git 存储库 -> https://github.com/cameronhenige/TestCrash 有人可以帮我弄清楚发生了什么吗?
import SwiftUI
struct ContentView: View {
@StateObject var testViewModel = TestViewModel()
var body: some View {
GeometryReader { proxy in
ScrollView {
VStack(alignment: .leading, spacing:0) {
TabView {
ForEach(testViewModel.images, id: \.self) { image in
Image(image)
}
}.tabViewStyle(PageTabViewStyle())
.clipShape(RoundedRectangle(cornerRadius: 15))
.padding()
.frame(width: proxy.size.width, height: proxy.size.height/2.5)
}
Button(action: {
testViewModel.removeFirst()
}) {
Text("Remove first item from list")
}
}
}.frame(maxWidth: .infinity).background(Color.black)
}
}
import Foundation
class TestViewModel: NSObject, ObservableObject {
@Published var images: [String] = ["dog", "cat", "bird"]
func removeFirst() {
images.remove(at: 0)
}
}
TabView {
ForEach(testViewModel.images, id: \.self) { image in
Image(image)
}
}.tabViewStyle(PageTabViewStyle())
.clipShape(RoundedRectangle(cornerRadius: 15))
.padding()
.frame(width: proxy.size.width, height: proxy.size.height/2.5)
.id(testViewModel.images.count)
向 TabView 添加 id 可以解决此问题!
有关为什么使用 .id(_:)
可以为您解决问题的更多解释,这是因为当 testViewModel.images.count
更改时(也就是视图现在使用不同的数据),您正在使视图无效,因为ID已更改。
有关使视图无效以及如何修复奇怪的视图更新的更多信息,请参阅 Demystify SwiftUI - WWDC21 演讲。