SwiftUI CoreData计算属性排序数组返回View2后不更新求助
CoreData关联实体排序数组更新异常解决方案
问题原因
你用的计算属性playersArrayRang依赖GameSession的关联玩家集合,但CoreData的NSSet关联在子实体(GamePlayer)的属性变化时,不会自动触发父实体(GameSession)的变更通知,导致SwiftUI视图无法感知到排序数组已经变化,所以修改分数后返回View2不会更新排序。
解决方案
方案1:让子实体变更触发父实体通知
在GamePlayer类中,当total_score属性变化时,主动通知关联的GameSession发送变更信号,这样依赖GameSession的视图会重新计算排序数组:
class GamePlayer: NSManagedObject { @NSManaged var total_score: Int32 @NSManaged var gameSession: GameSession? override func willChangeValue(forKey key: String) { super.willChangeValue(forKey: key) // 当分数变化时,通知关联的游戏会话更新 if key == "total_score", let session = gameSession { session.objectWillChange.send() } } }
方案2:改用@FetchRequest在视图中直接排序(推荐)
放弃实体里的计算属性,直接在View2中用@FetchRequest过滤当前GameSession的玩家并排序,CoreData会自动追踪子实体的变化并更新结果集:
struct View2: View { let session: GameSession @FetchRequest var players: FetchedResults<GamePlayer> init(session: GameSession) { self.session = session // 初始化FetchRequest:过滤属于当前session的玩家,按分数降序排序 _players = FetchRequest( entity: GamePlayer.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \GamePlayer.total_score, ascending: false)], predicate: NSPredicate(format: "gameSession == %@", session) ) } var body: some View { List(players) { player in Text("\(player.name ?? ""): \(player.total_score)") } } }
方案3:手动强制视图刷新(临时方案)
如果一定要保留实体里的计算属性,可以在View2中监听GameSession和所有关联玩家的变更信号,通过修改视图id强制重新渲染:
struct View2: View { @ObservedObject var session: GameSession @State private var refreshId = UUID() // 原计算属性 var playersArrayRang: [GamePlayer] { let players = session.players?.allObjects as? [GamePlayer] ?? [] return players.sorted { $0.total_score > $1.total_score } } var body: some View { List(playersArrayRang) { player in Text("\(player.name ?? ""): \(player.total_score)") // 监听单个玩家的变更 .onReceive(player.objectWillChange) { _ in refreshId = UUID() } } // 监听游戏会话的变更 .onReceive(session.objectWillChange) { _ in refreshId = UUID() } // 通过id变化强制视图重新计算排序数组 .id(refreshId) } }
内容的提问来源于stack exchange,提问作者user20587286
相关产品推荐
相关产品推荐

