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

如何实现CharacterAttributes字典变更时自动更新CharacterStats字典值?

实现字典值变更时自动更新关联字典的几种方案

针对你的需求,Swift字典属于引用类型,直接给attributes加didSet只会在替换整个字典实例时触发,修改单个键值对不会生效。下面是几种可行的实现方式:

方案一:封装成模型类/结构体,通过方法修改属性值

把两个字典封装到一个模型里,提供专门的方法修改属性值,每次修改后自动同步更新stats:

enum CharacterAttributes: String, Codable  {
    case strength, constitution, dexterity, intelligence
}

enum CharacterStats: String, Codable  {
    case maxHealthPoint, maxTacticPoint, maxActionPoint, movementSpeed
}

struct CharacterModel {
    private var attributes = [CharacterAttributes: Float]()
    var stats = [CharacterStats: Float]()
    
    // 修改属性的方法,内置更新逻辑
    mutating func setAttribute(_ key: CharacterAttributes, to value: Float) {
        attributes[key] = value
        updateStats()
    }
    
    // 获取属性值的方法
    func getAttribute(_ key: CharacterAttributes) -> Float? {
        attributes[key]
    }
    
    // 统一处理stats的计算逻辑
    private mutating func updateStats() {
        let constitution = attributes[.constitution] ?? 0
        let dexterity = attributes[.dexterity] ?? 0
        let intelligence = attributes[.intelligence] ?? 0
        
        stats[.maxHealthPoint] = constitution * 100
        stats[.maxTacticPoint] = (dexterity + intelligence) * 1.5
        stats[.maxActionPoint] = constitution * 10
        stats[.movementSpeed] = dexterity + 70
    }
}

// 使用示例
var character = CharacterModel()
character.setAttribute(.constitution, to: 5)
print(character.stats[.maxHealthPoint]) // 输出500.0
character.setAttribute(.dexterity, to: 10)
print(character.stats[.movementSpeed]) // 输出80.0

这种方式逻辑清晰,把属性修改和stats更新的逻辑绑定在一起,避免外部直接操作字典导致遗漏更新。

方案二:自定义可观察字典子类

如果不想封装成模型,可以自定义字典子类,重写下标方法,在设置值时自动触发更新:

class ObservableAttributeDictionary: [CharacterAttributes: Float] {
    // 定义值变化时的回调闭包
    var onValueChanged: (() -> Void)?
    
    override subscript(key: CharacterAttributes) -> Float? {
        get {
            super[key]
        }
        set {
            super[key] = newValue
            onValueChanged?()
        }
    }
}

// 使用示例
var attributes = ObservableAttributeDictionary()
var stats = [CharacterStats: Float]()

// 设置值变化后的更新逻辑
attributes.onValueChanged = {
    let constitution = attributes[.constitution] ?? 0
    let dexterity = attributes[.dexterity] ?? 0
    let intelligence = attributes[.intelligence] ?? 0
    
    stats[.maxHealthPoint] = constitution * 100
    stats[.maxTacticPoint] = (dexterity + intelligence) * 1.5
    stats[.maxActionPoint] = constitution * 10
    stats[.movementSpeed] = dexterity + 70
}

attributes[.constitution] = 3
print(stats[.maxHealthPoint]) // 输出300.0
attributes[.dexterity] = 8
print(stats[.movementSpeed]) // 输出78.0

这种方式保留了字典的原生使用习惯,同时通过闭包回调实现自动更新。

方案三:使用Combine框架(响应式场景)

如果你的项目基于SwiftUI或采用响应式编程,可以用Combine的CurrentValueSubject包装属性字典,订阅变化并更新stats:

import Combine

enum CharacterAttributes: String, Codable  {
    case strength, constitution, dexterity, intelligence
}

enum CharacterStats: String, Codable  {
    case maxHealthPoint, maxTacticPoint, maxActionPoint, movementSpeed
}

var attributesSubject = CurrentValueSubject<[CharacterAttributes: Float], Never>([:])
var stats = [CharacterStats: Float]()

// 订阅属性变化事件
var cancellable = attributesSubject.sink { attributes in
    let constitution = attributes[.constitution] ?? 0
    let dexterity = attributes[.dexterity] ?? 0
    let intelligence = attributes[.intelligence] ?? 0
    
    stats[.maxHealthPoint] = constitution * 100
    stats[.maxTacticPoint] = (dexterity + intelligence) * 1.5
    stats[.maxActionPoint] = constitution * 10
    stats[.movementSpeed] = dexterity + 70
}

// 修改属性值(需手动发送通知,因为字典是引用类型)
attributesSubject.value[.constitution] = 4
attributesSubject.send(attributesSubject.value)
print(stats[.maxHealthPoint]) // 输出400.0

也可以通过创建新字典实例的方式触发通知:

attributesSubject.value = attributesSubject.value.merging([.dexterity: 6]) { $1 }

总结

  • 简单场景优先选方案一,模型封装逻辑清晰易维护;
  • 想保留字典原生用法选方案二;
  • SwiftUI或响应式项目优先方案三。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 10:35:53