CoreData实体在SwiftUI视图间传递异常:点击任意行均显示首个实体
解决SwiftUI详情页显示错误Trip实体的问题
问题原因
你当前的实现里,所有TripRow都绑定了同一个viewRouter.isShowingDetailTripView布尔状态。当点击任意行触发这个状态变为true时,所有TripRow的fullScreenCover都会尝试渲染对应的DetailTripView,但SwiftUI只会显示其中一个(通常是列表中第一个被渲染的Trip对应的详情页),导致无论点击哪一行,详情页都显示同一个错误的Trip实体。
解决方案
改用fullScreenCover(item:)绑定方式,通过在ViewRouter中存储选中的Trip实体来控制详情页展示,具体步骤如下:
1. 修改ViewRouter
把原来的布尔状态替换为可选的Trip对象,用来存储用户选中的Trip:
class ViewRouter: ObservableObject { @Published var selectedTrip: Trip? // 替换原有的isShowingDetailTripView }
2. 更新TripRow代码
使用item绑定替代isPresented,点击时将当前Trip赋值给ViewRouter的selectedTrip:
struct TripRow: View { @EnvironmentObject var viewRouter: ViewRouter var trip: Trip var body: some View { // ... 你的TripRow原有内容 .fullScreenCover(item: $viewRouter.selectedTrip) { selectedTrip in DetailTripView(trip: selectedTrip) .environmentObject(viewRouter) } .onTapGesture { viewRouter.selectedTrip = trip // 赋值当前选中的Trip } } }
3. 让Trip实体遵循Identifiable协议
CoreData实体可通过扩展实现Identifiable,确保fullScreenCover(item:)能正确识别唯一实体:
extension Trip: Identifiable {}
4. 清理TripView无用代码
删除TripView中未使用的@State var tappedTrip = 0:
struct TripView: View { @EnvironmentObject var viewRouter: ViewRouter @FetchRequest(entity: Trip.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \Trip.startDate, ascending: true)], predicate: nil, animation: .linear) var trips: FetchedResults<Trip> var body: some View { VStack(spacing: 20) { ForEach(trips, id: \.self) { trip in TripRow(trip: trip) .environmentObject(viewRouter) } } } }
原理说明
fullScreenCover(item:)会根据绑定的可选对象是否非nil来决定是否展示详情页,且对象更新时会自动传递对应实体给详情页。这种方式确保每次点击不同的TripRow时,详情页显示的都是用户选中的那个Trip实体,避免了多个fullScreenCover共用同一个布尔开关导致的冲突问题。
内容的提问来源于stack exchange,提问作者Geheiligt
相关产品推荐
相关产品推荐

