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

修改@Published结构体嵌套属性时如何触发didSet方法?

嘿,这个问题我之前也碰到过!其实这不是Swift的设计变更,而是Xcode 11.4修复了之前的行为异常,回到了@Published的正确逻辑上:

@Published修饰的值类型属性,只有在整个属性被重新赋值的时候,才会触发didSet方法,同时向SwiftUI发送数据变更通知。你的PaddingRect是结构体(值类型),直接修改它的内部属性(比如paddingRect.left += 20)并没有对paddingRect本身执行赋值操作,所以didSet不会被触发,SwiftUI也不会收到更新通知(不过结构体的属性确实已经被修改了,只是视图和didSet没响应而已)。

下面给你几个可行的解决方案:

方案1:手动触发更新+抽离业务逻辑

如果你想保留结构体的设计,可以在修改内部属性后,手动调用objectWillChange.send()通知SwiftUI更新视图,同时把didSet里的逻辑抽成独立方法手动调用:

final class SomeStore : ObservableObject {
    @Published var someOtherValue: String = "Waiting for didSet"
    @Published var paddingRect:PaddingRect = PaddingRect() {
        didSet {
            updateSomeOtherValue()
        }
    }
    
    // 把didSet里的逻辑抽出来,方便手动调用
    func updateSomeOtherValue() {
        someOtherValue = "didSet fired"
    }
}

// 修改Button的action逻辑:
Button(action: {
    self.store.paddingRect.left += 20
    self.store.objectWillChange.send() // 手动通知视图更新
    self.store.updateSomeOtherValue() // 触发原本didSet里的逻辑
}) {
    Text("Padding left +20")
}

方案2:将结构体改为ObservableObject类

把PaddingRect改成遵循ObservableObject的引用类型(class),内部属性用@Published修饰,然后在SomeStore中监听它的变更:

// 把结构体改成class并遵循ObservableObject
class PaddingRect: ObservableObject {
    @Published var left: CGFloat = 20
    @Published var right: CGFloat = 20
}

final class SomeStore : ObservableObject {
    @Published var someOtherValue: String = "Waiting for didSet"
    @Published var paddingRect: PaddingRect = PaddingRect()
    
    init() {
        // 监听paddingRect的内部属性变化,触发我们需要的逻辑
        _ = paddingRect.objectWillChange.sink { [weak self] _ in
            self?.someOtherValue = "didSet fired"
        }
    }
}

// 视图里的Button不需要额外修改,直接改内部属性即可:
Button(action: {
    self.store.paddingRect.left += 20
}) {
    Text("Padding left +20")
}

这种方式下,修改paddingRect.left会触发PaddingRect内部的@Published发送通知,SwiftUI会自动更新视图,同时我们通过sink监听这个变更来更新someOtherValue。

方案3:重新赋值整个结构体(你已经发现的方法)

每次修改结构体属性时,创建一个新的结构体实例赋值给paddingRect,这样会触发didSet和@Published的变更通知:

Button(action: {
    self.store.paddingRect = PaddingRect(
        left: self.store.paddingRect.left + 20,
        right: self.store.paddingRect.right
    )
}) {
    Text("Padding left +20")
}

这个方法最直接,但如果结构体的属性很多,写起来会比较繁琐,适合简单结构体的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 06:57:43