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

SwiftUI中@State变量didSet未触发,用onChange响应是否正确?

SwiftUI状态响应疑问:@State的didSet未触发,但onChange正常工作

代码示例

GameView(SwiftUI视图)

struct GameView: View {
    @State private var userWon: Bool = false {
        didSet {
            print("userWon: \(userWon)") // 未被调用
            // TODO: 在这里修改游戏状态
        }
    }
    
    var body: some View {
        ZStack {
            VStack {
                GameViewRepresentable(userWon: $userWon)
                    .onChange(of: userWon) { newValue in
                        print("GameViewRepresentable: \(newValue)") // 正常调用
                        // TODO: 还是在这里修改游戏状态?
                    }
            }
            .clipped()
        }
    }
}

GameViewRepresentable(UIViewRepresentable)

struct GameViewRepresentable: UIViewRepresentable {
    typealias UIViewType = GameView
    @Binding var userWon: Bool {
        willSet {
            print("willSet userWon: \(newValue)")
        }
        didSet {
            print("didSet userWon: \(userWon)")
        }
    }
    
    func makeUIView(context: Context) -> GameView {
        let gameView = GameView()
        gameView.delegate = context.coordinator
        return gameView
    }

    func updateUIView(_ uiView: GameView, context: Context) {
    }

    func makeCoordinator() -> GameViewCoordinator {
        GameViewCoordinator(self)
    }

    class GameViewCoordinator: GameViewDelegate  {
        var parent: GameViewRepresentable
        
        init(_ parent: GameViewRepresentable) {
            self.parent = parent
        }

        func userWon() {
            self.parent.userWon = true
        }
    }
}

问题现象

协调器中的userWon()方法被正确调用,GameViewRepresentable中@Binding var userWon的willSet和didSet均触发,但GameView里@State private var userWon的didSet从未执行。不过GameView中的.onChange(of: userWon)能正常响应状态变化。想确认:这种用onChange响应状态变化的方式是否正确?原本预期@State的didSet会被调用。


解答

这是SwiftUI的正常行为,并非代码问题:

  • @State是SwiftUI框架内部管理的属性包装器,当通过Binding从外部修改其值时,框架会直接更新底层的状态存储,不会触发属性的didSet/willSet钩子——这些钩子仅在视图内部直接给@State变量赋值时才会生效。
  • 你当前使用.onChange(of: userWon)是响应状态变化的正确且推荐的方式,它专门用于监听SwiftUI状态属性的变更,无论这个变更是来自视图内部还是外部的Binding传递,都能可靠触发。

如果更倾向于使用didSet的写法,也可以改用@ObservableObject(或@StateObject)管理状态:

class GameState: ObservableObject {
    @Published var userWon: Bool = false {
        didSet {
            print("userWon didSet: \(userWon)")
            // 在这里处理游戏状态变更
        }
    }
}

struct GameView: View {
    @StateObject private var gameState = GameState()
    
    var body: some View {
        ZStack {
            VStack {
                GameViewRepresentable(userWon: $gameState.userWon)
            }
            .clipped()
        }
    }
}

这种方式下,无论通过Binding还是直接修改gameState.userWon,didSet都会正常触发。

综上,你当前用onChange响应状态变化的做法完全符合SwiftUI的状态管理逻辑,无需纠结@State的didSet未触发的问题——这就是框架的设计规则。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 16:25:19