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

SwiftUI自定义View无相关变更却重绘body的原因咨询

SwiftUI自定义View无相关变更却重绘body的原因咨询

嘿,我来帮你拆解下这个问题~ 你遇到的情况在SwiftUI开发里挺常见的,咱们一步步捋清楚:

首先得回忆下SwiftUI的重绘逻辑:当一个View依赖的状态(比如@State、@Published属性)发生变化时,它的body会被重新计算;同时父View的body重绘时,会重新创建所有子View的实例(因为View都是值类型的struct)。但正常来说,如果子View的输入参数没有变化,SwiftUI会跳过它的body渲染——前提是这个View遵循了Equatable协议。

回到你的代码里,第二个DemoDayView绑定的是viewModel.monthDate,你明明只修改了dayDate,它却跟着重绘,大概率是以下原因:

  • 你的DemoDayView没有遵循Equatable协议:SwiftUI默认无法判断两个DemoDayView实例是否等价,哪怕传入的date完全一样,当父View重绘时,它会默认认为这个子View的状态变了,从而触发body重绘。解决办法很简单,让DemoDayView遵循Equatable:

    struct DemoDayView: View, Equatable {
        static func == (lhs: DemoDayView, rhs: DemoDayView) -> Bool {
            // 这里比较所有影响View渲染的参数,比如date
            lhs.date == rhs.date
        }
    
        let date: Date
        // 其他View代码...
    }
    

    要是你的View参数都是Equatable类型,甚至可以直接用自动合成的实现,不用自己写==方法:

    struct DemoDayView: View, Equatable {
        let date: Date
        // 其他View代码...
    }
    
  • 另一种小概率可能:viewModel.monthDate被间接修改了:虽然你在tap手势里只改了dayDate,但可以检查下viewModel里有没有其他逻辑,比如修改dayDate时不小心连带更新了monthDate?或者monthDate是计算属性,它的依赖值悄悄变了?不过这种情况相对少见,先优先检查Equatable的问题。

另外补充个小技巧:如果你不想让某个子View跟着父View重绘,除了遵循Equatable,还可以给View加.equatable()修饰符,或者设置一个稳定的id,不过遵循Equatable是最规范的做法。

备注:内容来源于stack exchange,提问作者kunass2

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.13 17:44:35