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
相关产品推荐
相关产品推荐

