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

Swift字典中如何用didSet仅监听特定key的赋值变化?

问题解答

直接给stats字典添加didSet无法实现仅在attackSpeed被设置新值时触发。因为字典的didSet会在整个字典内容发生任何变更(比如添加、修改、删除任意key)时都会触发,没法精准定位到某个特定key的变化。

下面提供几种可行的实现方案:

方案1:封装成自定义结构体(推荐)

把玩家统计数据封装成结构体,给特定属性单独加didSet,逻辑更清晰,也方便后续扩展:

enum PlayerStats: String, Codable  {
    case maxHealthPoint
    case maxActionPoint
    case HP
    case AP
    case movementSpeed
    case attackSpeed
}

struct PlayerStatsHolder {
    var maxHealthPoint: Float = 0
    var maxActionPoint: Float = 0
    var HP: Float = 0
    var AP: Float = 0
    var movementSpeed: Float = 0
    // 仅给attackSpeed添加didSet
    var attackSpeed: Float = 0 {
        didSet {
            print("攻击速度已更新为: \(attackSpeed)")
            // 这里写你需要执行的逻辑
        }
    }
    
    // 可选:提供转字典的方法,兼容原有字典使用场景
    func toDictionary() -> [PlayerStats: Float] {
        return [
            .maxHealthPoint: maxHealthPoint,
            .maxActionPoint: maxActionPoint,
            .HP: HP,
            .AP: AP,
            .movementSpeed: movementSpeed,
            .attackSpeed: attackSpeed
        ]
    }
}

// 使用示例
var statsHolder = PlayerStatsHolder()
statsHolder.attackSpeed = 1.5 // 触发didSet逻辑
statsHolder.HP = 100 // 不会触发attackSpeed的didSet

方案2:给字典加自定义设置方法

如果必须保留字典结构,可以封装一个专门的设置函数,在函数内判断目标key再执行逻辑:

enum PlayerStats: String, Codable  {
    case maxHealthPoint
    case maxActionPoint
    case HP
    case AP
    case movementSpeed
    case attackSpeed
}

var stats = [PlayerStats: Float]()

func setStat(_ key: PlayerStats, value: Float) {
    let oldValue = stats[key]
    stats[key] = value
    // 仅当key是attackSpeed且值确实变化时执行逻辑
    if key == .attackSpeed && oldValue != value {
        print("攻击速度从\(oldValue ?? 0)更新为\(value)")
        // 这里写你需要触发的逻辑
    }
}

// 使用示例
setStat(.attackSpeed, value: 2.0) // 触发逻辑
setStat(.HP, value: 80) // 不触发

方案3:使用属性包装器(进阶)

自定义属性包装器,实现对字典特定key的监听:

enum PlayerStats: String, Codable  {
    case maxHealthPoint
    case maxActionPoint
    case HP
    case AP
    case movementSpeed
    case attackSpeed
}

@propertyWrapper
struct TrackedKeyDictionary<Key: Hashable, Value> {
    private var dictionary: [Key: Value]
    let trackedKey: Key
    var onChange: ((Value?, Value) -> Void)?
    
    init(wrappedValue: [Key: Value], trackedKey: Key) {
        self.dictionary = wrappedValue
        self.trackedKey = trackedKey
    }
    
    var wrappedValue: [Key: Value] {
        get { dictionary }
        set {
            let oldValue = dictionary[trackedKey]
            dictionary = newValue
            guard let newValueForKey = newValue[trackedKey], oldValue != newValueForKey else {
                return
            }
            onChange?(oldValue, newValueForKey)
        }
    }
}

// 使用示例
@TrackedKeyDictionary(wrappedValue: [:], trackedKey: PlayerStats.attackSpeed)
var stats: [PlayerStats: Float]

// 设置监听逻辑
stats.onChange = { oldValue, newValue in
    print("攻击速度变化:旧值\(oldValue ?? 0),新值\(newValue)")
}

stats[.attackSpeed] = 1.8 // 触发监听
stats[.movementSpeed] = 5.0 // 不触发

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 10:04:54