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

