SwiftUI跨List拖拽崩溃:拖拽到单元格触发NSInternalInconsistencyException
SwiftUI跨List拖拽崩溃问题
问题描述
实现了两个SwiftUI List间的拖拽功能,拖拽到列表项间隙时正常,但拖拽到单元格本身时,应用会在释放拖拽前直接崩溃。
已移除dropDestination内所有代码逻辑,崩溃仍会发生,且dropDestination代码从未被调用。询问这是SwiftUI的bug还是实现问题。
崩溃复现

代码实现
var body2: some View { HStack { VStack { Text("title-pending") List { ForEach(viewModel.pendingOrders) { order in RestaurantOrderCardView(order: order) .background(cardBackground) .draggable(order) } .listRowSeparator(.hidden) .listRowBackground(Color.clear) .padding(.top) } .listStyle(.plain) .background(listBackground) } VStack { Text("title-in-preparation") List { ForEach(viewModel.inPreparationOrders) { item in RestaurantOrderCardView(order: item) .background(cardBackground) } .dropDestination(for: RestaurantOrder.self) { items, offset in guard let firstItem = items.first else { return } withAnimation { viewModel.dropItem(firstItem, offset: offset) } } .listRowSeparator(.hidden) .listRowBackground(Color.clear) .padding(.top) } .listStyle(.plain) .background { if !viewModel.inPreparationOrders.isEmpty { listBackground } } .overlay { if viewModel.inPreparationOrders.isEmpty { RoundedRectangle(cornerRadius: 8) .foregroundColor(!inDropArea ? .grayBackgroundColor : .grayBackgroundColor.opacity(0.25)) .ignoresSafeArea() .dropDestination(for: RestaurantOrder.self) { items, location in guard let firstItem = items.first else { return false } withAnimation { viewModel.dropItem(firstItem, offset: 0) } return true } isTargeted: { inDropArea in withAnimation { self.inDropArea = inDropArea } } } } } } }
崩溃日志
2023-01-06 11:25:05.995303+0100 SimplifyStayAdmin[78761:2158775] *** Assertion failure in -[_UICollectionViewDragAndDropController _beginDragAndDropInsertingItemAtIndexPath:], _UICollectionViewDragAndDropController.m:620 2023-01-06 11:25:06.074407+0100 SimplifyStayAdmin[78761:2158775] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Could not get the cell at indexPath <NSIndexPath: 0x8846e25efd6dfbf1> {length = 2, path = 0 - 0} to start the reording portion of the Drag-and-drop' *** First throw call stack: ( 0 CoreFoundation 0x000000018040e7c8 __exceptionPreprocess + 172 1 libobjc.A.dylib 0x0000000180051144 objc_exception_throw + 56 2 Foundation 0x0000000180b13b98 _userInfoForFileAndLine + 0 3 UIKitCore 0x0000000109a546ec -[_UICollectionViewDragAndDropController _beginDragAndDropInsertingItemAtIndexPath:] + 540 4 UIKitCore 0x0000000109a53064 -[_UICollectionViewDragAndDropController beginReorderingForItemAtIndexPath:cell:] + 204 5 UIKitCore 0x0000000109a1bad0 -[UICollectionView _beginInteractiveMovementForItemAtIndexPath:] + 196 6 UIKit 0x000000011803040c -[UICollectionViewAccessibility beginInteractiveMovementForItemAtIndexPath:] + 80 7 UIKitCore 0x0000000109a5c55c -[_UICollectionViewDragDestinationController _reorderingDisplayLinkDidTick] + 912 8 QuartzCore 0x0000000187dd04f8 _ZN2CA7Display11DisplayLink14dispatch_itemsEyyy + 808 9 QuartzCore 0x0000000187ec89a8 _ZL22display_timer_callbackP12__CFMachPortPvlS1_ + 336 10 CoreFoundation 0x000000018033ee94 __CFMachPortPerform + 172 11 CoreFoundation 0x000000018037387c __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 56 12 CoreFoundation 0x0000000180372e9c __CFRunLoopDoSource1 + 496 13 CoreFoundation 0x000000018036d43c __CFRunLoopRun + 2176 14 CoreFoundation 0x000000018036c7a4 CFRunLoopRunSpecific + 584 15 GraphicsServices 0x0000000188ff7c98 GSEventRunModal + 160 16 UIKitCore 0x000000010a1f237c -[UIApplication _run] + 868 17 UIKitCore 0x000000010a1f6374 UIApplicationMain + 124 18 SwiftUI 0x000000010e6150d4 OUTLINED_FUNCTION_51 + 496 19 SwiftUI 0x000000010e614f7c OUTLINED_FUNCTION_51 + 152 20 SwiftUI 0x000000010dd7ab60 OUTLINED_FUNCTION_10 + 88 21 SimplifyStayAdmin 0x000000010044d0c4 $s17SimplifyStayAdmin0abC3AppV5$mainyyFZ + 40 22 SimplifyStayAdmin 0x000000010044d378 main + 12 23 dyld 0x00000001080c1fa0 start_sim + 20 24 ??? 0x00000001081c9e50 0x0 + 4431060560 25 ??? 0x0869800000000000 0x0 + 606156362346397696 ) libc++abi: terminating with uncaught exception of type NSException *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Could not get the cell at indexPath <NSIndexPath: 0x8846e25efd6dfbf1> {length = 2, path = 0 - 0} to start the reording portion of the Drag-and-drop' terminating with uncaught exception of type NSException CoreSimulator 857.14 - Device: iPad (10th generation) (D79A0AD8-4970-4F84-A5F9-078DAFB697A3) - Runtime: iOS 16.2 (20C52) - DeviceType: iPad (10th generation)
解决方案
这是iOS 16.x版本SwiftUI List拖拽的已知bug,根源是底层UICollectionView尝试获取拖拽目标单元格时失败,可通过以下方式修复:
方案1:禁用目标List的内部重排序
给目标List添加环境变量,阻止系统触发内部重排序逻辑,避免与跨List拖拽冲突:
List { // 原有列表内容 } .environment(\.editMode, .constant(.inactive)) .listStyle(.plain)
方案2:调整dropDestination的作用范围
不要将dropDestination附加在ForEach上,直接绑定到List本身,避免系统将单元格识别为重排序目标:
List { ForEach(viewModel.inPreparationOrders) { item in RestaurantOrderCardView(order: item) .background(cardBackground) } .listRowSeparator(.hidden) .listRowBackground(Color.clear) .padding(.top) } .dropDestination(for: RestaurantOrder.self) { items, offset in guard let firstItem = items.first else { return false } withAnimation { viewModel.dropItem(firstItem, offset: offset) } return true } .listStyle(.plain)
额外检查:如果RestaurantOrderCardView有自定义手势或交互逻辑,暂时移除测试是否干扰系统拖拽识别。
内容的提问来源于stack exchange,提问作者Dorian Pavetić
相关产品推荐
相关产品推荐

