使用 NavigationView 和工作表删除元素时 ForEach 崩溃
Posted
技术标签:
【中文标题】使用 NavigationView 和工作表删除元素时 ForEach 崩溃【英文标题】:Crash in ForEach when deleting element with NavigationView and sheet 【发布时间】:2021-08-12 13:07:00 【问题描述】:使用 Xcode 13 的新 binding variant 或 ForEach
时,当从 @Published
属性支持的内容中删除除最后一个元素之外的任何元素时,我的应用程序在设备上可预见地崩溃(但在模拟器中工作)。
奇怪的是,这只发生在视图包含在 NavigationView
中并附有工作表时。
这是一个演示该问题的独立应用程序:
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 中的错误吗?
【问题讨论】:
注意:MyView 应该是一个结构体 【参考方案1】:在 macos 12.beta、xcode 13.beta、target ios 15 和 macCatalyst 上非常适合我。 在 Mac、iPhone 和 iPad 上测试。可能在旧系统上有所不同。
编辑:使用 EnvironmentObject,这是我在测试中使用的代码:
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")
]
【讨论】:
很难相信它会有所不同,但又一次。 一小时前刚刚更新到 xcode 13.0-beta5 我仍然有 xcode 13.0-beta4,和那个 xcode 一样好用。 您的回答帮助我发现了真正的问题。有关详细信息,请参阅我编辑的问题。 您的新代码对我仍然有效。有关我所做的细微更改,请参阅我的答案 EDIT。你的代码在哪一行崩溃了?以上是关于使用 NavigationView 和工作表删除元素时 ForEach 崩溃的主要内容,如果未能解决你的问题,请参考以下文章
如何从 SwiftUI 中的 NavigationView 中删除搜索栏?