2017-09-24 101 views
4

我正在实现一个WeakSet,它将其元素弱地包装在WeakWrapper中,以便不增加其保留数。实现在WeakSet中跳过零元素的自定义迭代器

我的问题是,我该如何创建一个迭代器,以便我可以遍历那些跳过那些已被释放的元素(即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

注意''==在你WeakWrapper未正确执行:它依赖于不同的对象有不同的哈希值,不必是真的。 –

+1

另外(除非我误),不需要'...&Hashable'的需求,因为你无处存取'T'对象的哈希值(只有它的对象标识符) –

+0

@Martin谢谢。我认为ObjectIdentifier总是为任何给定的程序运行返回一个唯一的值?也许是一个新的SO问题的话题。 – MH175

回答

2

一种可能的方案,使用来自夫特 标准库内置方法:

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()) 
    } 
}