В Swift 3, я хотел бы иметь возможность создать протокол, который позволяет мне добавлять элементы и выполнять итерацию с помощью for element in
. Протокол должен работать как на NSMutableSet
, так и на NSMutableOrderedSet
(так как они не наследуются от того же класса).Протокол моста NSMutableSet и NSMutableOrderedSet вместе
Я знаю, что есть веские причины, почему NSMutableSet
и NSMutableOrderedSet
не наследуют от того же класса, что объясняется here и here.
Но я хочу создать протокол, который использует только часть всех методов внутри 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<NSObject>> // 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
? Как я должен это делать? Я пробовал различные комбинации typealias
и associatedtype
из Element
, Iterator
и т. Д. Я также пробовал this answer, он не работает для меня.
EDIT 2: Ответ на свой вопрос в EDIT 1
Я получил var count: Int { get }
работать, используя это решение, не уверен, что это лучший один, хотя ... Также было бы неплохо, чтобы не имея внесите var elements: [Any] { get }
в расширение NSMutableSet
и NSMutableOrderedSet
, , но я предполагаю, что это неизбежно?
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<Element>: MutableSet {
private let _add: (Any) ->()
private let _makeIterator:() -> AnyIterator<Element>
private var _getElements:() -> [Any]
private var _getCount:() -> Int
func add(_ element: Any) { _add(element) }
func makeIterator() -> AnyIterator<Element> { return _makeIterator() }
var count: Int { return _getCount() }
var elements: [Any] { return _getElements() }
init<MS: MutableSet>(_ 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<Any>
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
EDIT 1: Развейте вопрос Используя отличный ответ на @ грабят-Napier с type erasure
техникой я продлил protocol MutableSet
, чтобы иметь возможность count
и также subscript
, но я только был в состоянии сделать поэтому используйте 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<Element>: MutableSet {
private var _getCount:() -> Int
private var _getElements:() -> [Any]
private let _add: (Any) ->()
private let _makeIterator:() -> AnyIterator<Element>
func getElements() -> [Any] { return _getElements() }
func add(_ element: Any) { _add(element) }
func makeIterator() -> AnyIterator<Element> { return _makeIterator() }
func getCount() -> Int { return _getCount() }
init<MS: MutableSet>(_ 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<Any>
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]
в протоколе, вместо функций?
'_getCount = {ms.count}' –
Спасибо! Да, я использовал это, см. Мой Edit 2, с таким решением! Хм ... так это решение тогда? Обертывание его в закрытии ... (подпись метода) – Sajjon
да; это простой способ превратить свойство в функцию. Я не понимаю второй вопрос, хотя об элементах. –