在ForEach中删除带有NavigationView和工作表的元素时崩溃



使用Xcode 13的ForEach的新绑定变体,当从@Published属性支持的内容中删除除最后一个元素以外的任何元素时,我的应用程序在设备上可预测地崩溃(但在模拟器中工作)。

奇怪的是,只有当视图包含在NavigationView中并且附加了一个sheet时,才会发生这种情况。

下面是一个独立的应用程序来演示这个问题:

import SwiftUI
struct Vegetable: Identifiable {
let id: UUID
let name: String
}
class MyModel: ObservableObject {
@Published var vegetables: [Vegetable] = [
Vegetable(id: UUID(), name: "Eggplant"),
Vegetable(id: UUID(), name: "Corn"),
Vegetable(id: UUID(), name: "Radish")
]
}
@main
struct SwiftUIForEachTestApp: App {
@StateObject var model = MyModel()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(model)
}
}
}
struct ContentView: View {
var body: some View {
// Remove the containing NavigationView and the crash disappears
NavigationView {
MyView()
}
}
}
struct MyView: View {
@EnvironmentObject private var model: MyModel
@State private var isPresentingSheet = false
var body: some View {
List {
ForEach($model.vegetables) { $vegetable in
Text(vegetable.name)
}
.onDelete { indices in model.vegetables.remove(atOffsets: indices) }
}
// Remove the sheet and the crash disappears
.sheet(isPresented: $isPresentingSheet) {
}
}
}

运行应用程序并删除顶部行导致以下崩溃(第16行对应@main):

#0  0x00000001a73a6eac in _swift_runtime_on_report ()
#1  0x00000001a741f100 in _swift_stdlib_reportFatalErrorInFile ()
#2  0x00000001a705e668 in closure #1 in closure #1 in closure #1 in _assertionFailure(_:_:file:line:flags:) ()
#3  0x00000001a705dce0 in _assertionFailure(_:_:file:line:flags:) ()
#4  0x00000001a703c6b4 in _ArrayBuffer._checkInoutAndNativeTypeCheckedBounds(_:wasNativeTypeChecked:) ()
#5  0x00000001a7041e2c in Array.subscript.read ()
#6  0x00000001a7041d58 in protocol witness for Collection.subscript.read in conformance [τ_0_0] ()
#7  0x0000000100320c38 in closure #1 in ForEach<>.init<τ_0_0>(_:id:content:) ()
#8  0x0000000100320f48 in partial apply for closure #1 in ForEach<>.init<τ_0_0>(_:id:content:) ()
#9  0x0000000100320fd8 in thunk for @escaping @callee_guaranteed (@in_guaranteed τ_1_0.Collection.Index) -> (@out τ_1_0.Collection.Index, @out τ_0_1) ()
#10 0x0000000100321090 in partial apply for thunk for @escaping @callee_guaranteed (@in_guaranteed τ_1_0.Collection.Index) -> (@out τ_1_0.Collection.Index, @out τ_0_1) ()
#11 0x00000001a7193d0c in LazyMapSequence<>.subscript.read ()
#12 0x00000001a71938e4 in protocol witness for Collection.subscript.read in conformance <> LazyMapSequence<τ_0_0, τ_0_1> ()
#13 0x00000001aa2a374c in ForEach.IDGenerator.makeID(data:index:offset:) ()
#14 0x00000001aa2abf54 in ForEachState.ForEachViewIDCollection.subscript.getter ()
#15 0x00000001aa2ac914 in ForEachState.ForEachViewIDCollection.subscript.read ()
#16 0x00000001aa2ac84c in protocol witness for Collection.subscript.read in conformance ForEachState<τ_0_0, τ_0_1, τ_0_2>.ForEachViewIDCollection ()
#17 0x00000001aa37a838 in _ViewList_ID._Views.subscript.getter ()
#18 0x00000001aa37a3f4 in protocol witness for Collection.subscript.read in conformance _ViewList_ID.Views ()
#19 0x00000001a71eaecc in Slice.subscript.getter ()
#20 0x00000001a71ed008 in Slice.subscript.read ()
#21 0x00000001a71ecf48 in protocol witness for Collection.subscript.read in conformance Slice<τ_0_0> ()
#22 0x00000001a7193cc8 in LazyMapSequence<>.subscript.read ()
#23 0x00000001a71938e4 in protocol witness for Collection.subscript.read in conformance <> LazyMapSequence<τ_0_0, τ_0_1> ()
#24 0x00000001aa157f44 in ShadowRowCollection.subscript.getter ()
#25 0x00000001aa1580ec in ShadowRowCollection.subscript.read ()
#26 0x00000001aa15802c in protocol witness for Collection.subscript.read in conformance ShadowRowCollection<τ_0_0> ()
#27 0x00000001aa365448 in ListCoreDataSource.rowID(at:) ()
#28 0x00000001aa004ec0 in closure #1 in performUpdates #1 <τ_0_0, τ_0_1>() in ListCoreCoordinator.updateUITableView(_:to:transaction:) ()
#29 0x00000001a9ffd09c in specialized _ArrayProtocol.filter(_:) ()
#30 0x00000001aa004658 in performUpdates #1 <τ_0_0, τ_0_1>() in ListCoreCoordinator.updateUITableView(_:to:transaction:) ()
#31 0x00000001aa00565c in closure #1 in ListCoreCoordinator.updateUITableView(_:to:transaction:) ()
#32 0x00000001a9ec6008 in thunk for @escaping @callee_guaranteed () -> () ()
#33 0x00000001a9eaee84 in static Update.end() ()
#34 0x00000001a9cd7390 in static NSRunLoop.flushObservers() ()
#35 0x00000001a9cd72d8 in closure #1 in closure #1 in static NSRunLoop.addObserver(_:) ()
#36 0x00000001a9cd2250 in specialized thunk for @callee_guaranteed () -> (@error @owned Error) ()
#37 0x00000001c9b53f24 in autoreleasepool<τ_0_0>(invoking:) ()
#38 0x00000001a9cd72b8 in closure #1 in static NSRunLoop.addObserver(_:) ()
#39 0x00000001a9cd7410 in @objc closure #1 in static NSRunLoop.addObserver(_:) ()
#40 0x00000001a3437588 in __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ ()
#41 0x00000001a34316ac in __CFRunLoopDoObservers ()
#42 0x00000001a3431c58 in __CFRunLoopRun ()
#43 0x00000001a3431308 in CFRunLoopRunSpecific ()
#44 0x00000001baab4734 in GSEventRunModal ()
#45 0x00000001a5eaf75c in -[UIApplication _run] ()
#46 0x00000001a5eb4fcc in UIApplicationMain ()
#47 0x00000001aa39c380 in closure #1 in KitRendererCommon(_:) ()
#48 0x00000001aa39c30c in runApp<τ_0_0>(_:) ()
#49 0x00000001a9e94b38 in static App.main() ()
#50 0x000000010031c9c4 in static SwiftUIForEachTestApp.$main() at /xxx/SwiftUIForEachTest/Shared/ContentView.swift:16
#51 0x000000010031e888 in main ()
#52 0x00000001a30edcf8 in start ()

这是SwiftUI的一个bug吗?

在macos 12上运行得很好。测试版,xcode 13。beta,目标ios 15和macatalyst。在mac、iPhone和iPad上进行了测试。

编辑:使用环境对象,这是我在测试中使用的代码:

import SwiftUI
@main
struct TestApp: App {
@StateObject var model = MyModel()  // <--- 
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(model)
}
}
}
struct ContentView: View {
@EnvironmentObject var model: MyModel // <---
var body: some View {
NavigationView {
MyView()
}
}
}
struct MyView: View {
@EnvironmentObject var model: MyModel  // <---
@State private var isPresentingSheet = false
var body: some View {
List {
ForEach($model.vegetables) { $vegetable in
Text(vegetable.name)
}
.onDelete { indices in model.vegetables.remove(atOffsets: indices) }
}
.sheet(isPresented: $isPresentingSheet) {
Text("the sheet")  // <----
}
}
}
struct Vegetable: Identifiable {
let id: UUID
let name: String
}
class MyModel: ObservableObject {
@Published var vegetables: [Vegetable] = [
Vegetable(id: UUID(), name: "Eggplant"),
Vegetable(id: UUID(), name: "Corn"),
Vegetable(id: UUID(), name: "Radish")
]
}

最新更新