在Swift结构中维护值语义,它包含对象引用

时间:2015-08-19 12:40:55

标签: swift swift2

我有一个包含内部存储对象的Swift结构。如何确保结构具有值语义?

public struct Times {
    private let times = NSMutableIndexSet()

    mutating func addTimeRange(openTime: Int, closeTime: Int) {
        self.times.addIndexesInRange(NSRange(location: openTime, length: closeTime - openTime))
    }
}

3 个答案:

答案 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