我有一个包含内部存储对象的Swift结构。如何确保结构具有值语义?
public struct Times {
private let times = NSMutableIndexSet()
mutating func addTimeRange(openTime: Int, closeTime: Int) {
self.times.addIndexesInRange(NSRange(location: openTime, length: closeTime - openTime))
}
}
答案 0 :(得分:3)
存储NSIndexSet而不是NSMutableIndexSet。这正是不可变超类存在的原因。
public struct Times {
private var times = NSIndexSet()
mutating func addTimeRange(openTime: Int, closeTime: Int) {
let t = NSMutableIndexSet(indexSet:self.times)
t.addIndexesInRange(NSRange(location: openTime, length: closeTime - openTime))
self.times = NSIndexSet(indexSet:t)
}
}
如果这是一个类而不是一个结构,你可以通过将times
声明为@NSCopying
然后只使用简单的赋值来自动执行最后一步:
public class Times {
@NSCopying private var times = NSIndexSet()
func addTimeRange(openTime: Int, closeTime: Int) {
let t = NSMutableIndexSet(indexSet:self.times)
t.addIndexesInRange(NSRange(location: openTime, length: closeTime - openTime))
self.times = t // ensure immutable copy
}
}
答案 1 :(得分:3)
Swift 3更新
Swift 3包含Foundation框架中许多类型的值类型。现在有一个IndexSet结构,它连接到NSIndexSet。内部实现类似于下面的Swift 2解决方案。
有关新基金会价值类型的详细信息,请参阅:https://github.com/apple/swift-evolution/blob/master/proposals/0069-swift-mutability-for-foundation.md
Swift 2中的旧方法
写时复制方法是正确的解决方案。但是,如果只有一个结构实例引用它,则无需创建NSMutableIndexSet的副本。 Swift提供了一个名为isUniquelyReferencedNonObjC()
的全局函数,用于确定纯Swift对象是否仅被引用一次。
由于我们不能将此函数与Objective-C类一起使用,我们需要在Swift类中包装NSMutableIndexSet。
public struct Times {
private final class MutableIndexSetWrapper {
private let mutableIndexSet: NSMutableIndexSet
init(indexSet: NSMutableIndexSet) {
self.mutableIndexSet = indexSet
}
init() {
self.mutableIndexSet = NSMutableIndexSet()
}
}
private let times = MutableIndexSetWrapper()
mutating func addTimeRange(openTime: Int, closeTime: Int) {
// Make sure our index set is only referenced by this struct instance
if !isUniquelyReferencedNonObjC(&self.times) {
self.times = MutableIndexSetWrapper(indexSet: NSMutableIndexSet(indexSet: self.times.mutableIndexSet))
}
let range = NSRange(location: openTime, length: closeTime - openTime)
self.times.mutableIndexSet.addIndexesInRange(range)
}
}
答案 2 :(得分:1)
使用Swift的本地String
类型可能是一个选项,它具有内置的值语义,因为它本身就是一个结构。
Set