You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI .swipeActions搭配Core Data时编辑sheet始终传入首条数据如何解决

问题原因

你的实现逻辑存在明确问题:你将sheet(isPresented:)修饰符放在了ForEach循环内部,且所有行共用同一个showingEditTripScreen布尔状态控制显隐。SwiftUI会预渲染列表所有行的视图结构,当你把showingEditTripScreen置为true时,只会触发最先渲染的第一行对应的sheet生效,因此永远传入第一条行程的数据。

可行解决方案

方案一(推荐):使用sheet(item:)API实现

这是苹果官方针对列表选中项弹窗场景设计的API,无需额外维护布尔显隐状态,自动匹配选中项对应的数据。

修改步骤:

  1. 新增可选类型的选中行程状态变量(需保证你的Trip模型遵守Identifiable协议,你当前在ForEach中已使用\.id作为唯一标识,默认满足要求):
@State private var selectedTrip: Trip?
  1. 将原写在ForEach内部的sheet修饰符移除,移动到List/父视图的外层
  2. 修改编辑按钮的点击逻辑,直接给selectedTrip赋值为当前点击的行程即可触发弹窗

完整修改后代码示例:

// sheet移到ForEach外层,比如放在List的修饰符位置
List {
    ForEach(tripVM.trips, id: \.id) { trip in
        TripCardView(trip: trip)
            .listRowSeparator(.hidden)
            .swipeActions(allowsFullSwipe: false) {
                // Edit Trip
                Button {
                    selectedTrip = trip // 直接赋值选中的行程
                } label: {
                    Label("Edit", systemImage: "pencil.circle.fill")
                }
                .tint(.green)
                
                // Delete Trip
                Button {
                    tripVM.deleteTrip(trip: trip)
                    tripVM.getAllTrips()
                } label: {
                    Label("Delete", systemImage: "trash.circle.fill")
                }
                .tint(.red)
            }
    }
}
.sheet(item: $selectedTrip, onDismiss: {
    selectedTrip = nil
}, content: { trip in
    EditTripScreen(trip: trip)
})

方案二:保留isPresented的兼容实现

如果你需要兼容更低版本或者特殊需求要保留原布尔控制逻辑,可以新增可选变量存储选中行程:

  1. 新增两个状态变量:
@State private var showingEditTripScreen = false
@State private var currentEditTrip: Trip?
  1. 编辑按钮点击时先赋值要编辑的行程,再修改显隐状态:
Button {
    currentEditTrip = trip
    showingEditTripScreen = true
} label: {
    Label("Edit", systemImage: "pencil.circle.fill")
}
  1. sheet同样移到ForEach外层,content中使用currentEditTrip传值:
.sheet(isPresented: $showingEditTripScreen, onDismiss: {
    currentEditTrip = nil
}, content: {
    if let trip = currentEditTrip {
        EditTripScreen(trip: trip)
    }
})
注意事项

不要将sheet、alert这类全局弹窗类修饰符放在ForEach循环内部,避免重复创建多份弹窗实例导致的取值、显隐异常。

内容的提问来源于stack exchange,提问作者diver91

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 15:27:01