协议将NSMutableSet和NSMutableOrderedSet桥接在一起

Swift 3中 ,我希望能够创建一个协议,允许我添加元素并迭代使用for element in 。 该协议应该适用于NSMutableSetNSMutableOrderedSet (因为它们不从同一个类inheritance)。

我知道NSMutableSetNSMutableOrderedSet没有从同一个类inheritance的原因很充分, 这里和这里都有解释。

但我想创建一个协议,它只使用NSMutableSet (和NSMutableOrderedSet )中所有方法的一小部分。

我只是add了工作,像这样:

 protocol MutableSet { func add(_ element: Any) } extension NSMutableSet: MutableSet {} extension NSMutableOrderedSet: MutableSet {} let one: NSString = "one" let two: NSString = "two" // Works if created with `NSMutableSet` let mutableSet: MutableSet = NSMutableSet() mutableSet.add(one) mutableSet.add(two) for element in mutableSet as! NSMutableSet { print(element) } /* This prints: one two */ // Also works if creating `NSMutableOrderedSet` instance let mutableOrderedSet: MutableSet = NSMutableOrderedSet() mutableOrderedSet.add(one) mutableOrderedSet.add(two) for element in mutableOrderedSet as! NSMutableOrderedSet { print(element) } /* This prints: one two */ 

但是我真的很想能够通过使用以下方式迭代元素:

 for element in mutableSet { print(element) } 

我试图使protocol MutableSet符合Sequence协议,类似这样,但它不起作用:

 protocol MutableSet: Sequence { func add(_ element: Any) } extension NSMutableSet: MutableSet { typealias Iterator = NSFastEnumerationIterator typealias Element = NSObject // I dont know what to write here typealias SubSequence = Slice<Set> // Neither here.... } let one: NSString = "one" let two: NSString = "two" let mutableSet: MutableSet = NSMutableSet() // Compile Error: Protocol `MutableSet` can only be used as a generic constraint because it has Self or associated type requirements mutableSet.add(one) mutableSet.add(two) for element in mutableSet { // Compile Error: Using `MutableSet` as a concrete type conforming to protocol `Sequence` is not supported print(element) } 

是否有可能使我的协议符合Sequence ? 我该怎么办? 我尝试过各种类型的typealiasassociatedtypeElementIterator等。我也试过这个答案它对我不起作用。

编辑2:在编辑1中回答我自己的问题

我得到了var count: Int { get }使用这个解决方案工作,不确定它是否是最好的…而且不必实现var elements: [Any] { get }在扩展名中NSMutableSetNSMutableOrderedSet但我想这是不可避免的?

 protocol MutableSet: Sequence { subscript(position: Int) -> Any { get } func add(_ element: Any) var count: Int { get } var elements: [Any] { get } } extension MutableSet { subscript(position: Int) -> Any { return elements[position] } } extension NSMutableSet: MutableSet { var elements: [Any] { return allObjects } } extension NSMutableOrderedSet: MutableSet { var elements: [Any] { return array } } struct AnyMutableSet: MutableSet { private let _add: (Any) -> () private let _makeIterator: () -> AnyIterator private var _getElements: () -> [Any] private var _getCount: () -> Int func add(_ element: Any) { _add(element) } func makeIterator() -> AnyIterator { return _makeIterator() } var count: Int { return _getCount() } var elements: [Any] { return _getElements() } init(_ ms: MS) where MS.Iterator.Element == Element { _add = ms.add _makeIterator = { AnyIterator(ms.makeIterator()) } _getElements = { ms.elements } _getCount = { ms.count } } } let one: NSString = "one" let two: NSString = "two" let mutableSet: AnyMutableSet let someCondition = true if someCondition { mutableSet = AnyMutableSet(NSMutableSet()) } else { mutableSet = AnyMutableSet(NSMutableOrderedSet()) } mutableSet.add(one) mutableSet.add(two) for i in 0..<mutableSet.count { print("Element[\(i)] == \(mutableSet[i])") } // Prints: // Element[0] == one // Element[1] == two 

编辑1:跟进问题使用@ rob-napier的优秀答案和type erasure技术我已经扩展了protocol MutableSet以具有countsubscript能力,但是我只能使用func (名为getCount )这样做丑陋,而不是var 。 这就是我正在使用的:

 protocol MutableSet: Sequence { subscript(position: Int) -> Any { get } func getCount() -> Int func add(_ element: Any) func getElements() -> [Any] } extension MutableSet { subscript(position: Int) -> Any { return getElements()[position] } } extension NSMutableSet: MutableSet { func getCount() -> Int { return count } func getElements() -> [Any] { return allObjects } } extension NSMutableOrderedSet: MutableSet { func getElements() -> [Any] { return array } func getCount() -> Int { return count } } struct AnyMutableSet: MutableSet { private var _getCount: () -> Int private var _getElements: () -> [Any] private let _add: (Any) -> () private let _makeIterator: () -> AnyIterator func getElements() -> [Any] { return _getElements() } func add(_ element: Any) { _add(element) } func makeIterator() -> AnyIterator { return _makeIterator() } func getCount() -> Int { return _getCount() } init(_ ms: MS) where MS.Iterator.Element == Element { _add = ms.add _makeIterator = { AnyIterator(ms.makeIterator()) } _getElements = ms.getElements _getCount = ms.getCount } } let one: NSString = "one" let two: NSString = "two" let mutableSet: AnyMutableSet let someCondition = true if someCondition { mutableSet = AnyMutableSet(NSMutableSet()) } else { mutableSet = AnyMutableSet(NSMutableOrderedSet()) } mutableSet.add(one) mutableSet.add(two) for i in 0..<mutableSet.getCount() { print("Element[\(i)] == \(mutableSet[i])") } // Prints: // Element[0] == one // Element[1] == two 

我怎样才能使用var count: Int { get }var elements: [Any]在协议中,而不是函数?

几乎所有“我如何使用PAT(具有相关类型的协议)……”的答案都是“把它放在一个盒子里”。 那个盒子是橡皮擦 。 在你的情况下,你想要一个AnyMutableSet

 import Foundation // Start with your protocol protocol MutableSet: Sequence { func add(_ element: Any) } // Now say that NSMutableSet is one. There is no step two here. Everything can be inferred. extension NSMutableSet: MutableSet {} // Create a type eraser for MutableSet. Note that I've gone ahead and made it generic. // You could lock it down to just Any, but why limit yourself struct AnyMutableSet: MutableSet { private let _add: (Any) -> () func add(_ element: Any) { _add(element) } private let _makeIterator: () -> AnyIterator func makeIterator() -> AnyIterator { return _makeIterator() } init(_ ms: MS) where MS.Iterator.Element == Element { _add = ms.add _makeIterator = { AnyIterator(ms.makeIterator()) } } } // Now we can use it let one: NSString = "one" let two: NSString = "two" // Wrap it in an AnyMutableSet let mutableSet = AnyMutableSet(NSMutableSet()) mutableSet.add(one) mutableSet.add(two) for element in mutableSet { print(element) } 

原则上还有另一种方法,即直接使用现有的“协议,它允许我添加元素并迭代使用元素。” 这是两个协议: SetAlgebra & Sequence 。 在实践中,我发现要获得NSMutableSetNSOrderedSet以符合SetAlgebra ……令人讨厌。 NSMutableSet基本上在Swift 3中被破坏。它在各个地方接受Any ,但被定义为在AnyHashable 。 基本代码不起作用:

 let s = NSMutableSet() let t = NSMutableSet() s.union(t) 

但那是因为你不应该使用NSMutableSet 。 它自动桥接到Set ,你应该使用Set代替。 Set确实符合SetAlgebra & Sequence所以没问题。

但后来我们来到NSOrderedSet 。 这很难融入Swift(这就是为什么基金会团队推迟了这么久)。 这真的是IMO类型的一团糟,每次我尝试使用它时,我都会将它拉出来,因为它不适合任何东西。 (尝试使用NSFetchedResultsController在“有序关系”中使用顺序。)坦率地说,最好的方法是将其包含在结构中,并使该结构符合SetAlgebra & Sequence

但是如果你不这样做(或者只是摆脱有序集合,就像我最终总是那样),那么类型擦除几乎是你唯一的工具。