Swift中如何让字典内的数组值可变?
Swift中字典内数组的高效修改方案
你遇到的问题本质是Swift的Array是值类型,从字典中取出数组时会生成副本,修改副本不会影响字典内原有的数组。下面是几种无需依赖NSDictionary/NSArray的解决方案:
1. 最简洁的写法:利用下标默认值(Swift 4+)
Swift 4及以上支持给字典下标指定默认值,直接一行代码完成判断、创建(如果需要)和追加操作:
var intsForString = [String:[Int]]() func add(value: Int, forKey: String) { intsForString[forKey, default: []].append(value) } add(value: 1, forKey: "a") add(value: 2, forKey: "a") print(intsForString["a"]!) // 输出 [1, 2]
这个语法会自动处理key不存在的情况:如果key不存在,先插入空数组到字典,再执行追加;如果key存在,直接对字典内的数组进行修改。得益于Swift的**写时复制(COW)**机制,只有当数组被修改且存在其他引用时才会触发复制,不会产生不必要的性能开销。
2. 兼容旧版本的手动处理方案
如果需要兼容Swift 4以下版本,可以用可选绑定的方式,但同样能借助COW保证效率:
var intsForString = [String:[Int]]() func add(value: Int, forKey: String) { if var ints = intsForString[forKey] { ints.append(value) intsForString[forKey] = ints } else { intsForString[forKey] = [value] } }
你担心的“重复查找键、数组复制”问题其实被Swift的COW优化抵消了:取出数组时如果没有其他引用,append操作不会复制数组,修改后存回字典的操作也只会更新一次键值对,性能开销极小。
3. 模拟引用语义:用类包装数组
如果想完全模拟Objective-C中引用类型的行为,可以自己定义一个持有数组的类(类是引用类型):
class WrappedArray<T> { var items = [T]() } var intsForString = [String:WrappedArray<Int>]() func add(value: Int, forKey: String) { let wrappedArray = intsForString[forKey] ?? WrappedArray<Int>() if intsForString[forKey] == nil { intsForString[forKey] = wrappedArray } wrappedArray.items.append(value) }
这种方式下,字典存储的是类实例的引用,修改wrappedArray.items会直接改变字典内实例的属性,不需要再将数组存回字典。
内容的提问来源于stack exchange,提问作者Thomas Tempelmann
相关产品推荐
相关产品推荐

