我正在实现一个WeakSet
,它将其元素弱地包裹在WeakWrapper
中,以便不增加其保留计数。
我的问题是,我如何创建一个迭代器,以便我可以遍历跳过那些已经解除分配的元素(即nil
)。
请注意,我正在尝试优化迭代;如果插入/删除相对较慢,那就没问题了,但设置迭代器的性能成本应该很低/没有。
这是WeakSet
的基本形式。我可以调用clean()
来删除其对象已被解除分配的WeakWrapper
:
struct WeakSet<T> where T: AnyObject & Hashable {
private var set: Set<WeakWrapper<T>> = []
mutating func insert(_ elem: T) {
self.set.insert(WeakWrapper<T>(elem))
}
mutating func remove(_ elem: T) {
self.set.remove(WeakWrapper<T>(elem))
}
mutating func clean() {
for elem in set {
if elem.obj == nil {
self.set.remove(elem)
}
}
}
}
fileprivate class WeakWrapper<T>: Hashable where T: AnyObject {
weak var obj: T?
let hashValue: Int
init(_ obj: T) {
self.obj = obj
self.hashValue = ObjectIdentifier(obj).hashValue
}
static func ==(lhs: WeakWrapper, rhs: WeakWrapper) -> Bool {
return lhs.hashValue == rhs.hashValue
}
}
我希望能够做到这样的事情,其中生成的元素是T
类型的基础非零元素,而不是包装元素:
class MyObject: NSObject {
func doSomething() { }
}
var weakSet = WeakSet<MyObject>()
for myObject in weakSet {
myObject.doSomething()
}
答案 0 :(得分:4)
一种可能的解决方案,使用Swift中的内置方法 标准库:
extension WeakSet: Sequence {
func makeIterator() -> AnyIterator<T> {
return AnyIterator(self.set.lazy.flatMap { $0.obj }.makeIterator())
}
}
从集合的懒惰视图开始,它的一个(懒惰)集合
使用flatMap
创建非零对象。
它也可以在没有lazy
的情况下工作,但随后是一个非零的数组
一旦调用makeIterator()
,就会急切地创建对象。
使用自定义迭代器类型的另一种解决方案:
struct WeakSetIterator<T>: IteratorProtocol where T: AnyObject {
fileprivate var iter: SetIterator<WeakWrapper<T>>
mutating func next() -> T? {
while let wrapper = iter.next() {
if let obj = wrapper.obj { return obj }
}
return nil
}
}
extension WeakSet: Sequence {
func makeIterator() -> WeakSetIterator<T> {
return WeakSetIterator(iter: self.set.makeIterator())
}
}