Ответ 1
Как и в Swift 4, в стандартной библиотеке нет методов
для перечисления элементов OptionSetType
(Swift 2) соответственно.
OptionSet
(Swift 3, 4).
Вот возможная реализация, которая просто проверяет каждый бит
базового исходного значения и для каждого установленного бита,
возвращается соответствующий элемент.
"Переполнение переполнения" &* 2
используется как сдвиг влево, потому что <<
определяется только для конкретных целых типов, но не для протокола IntegerType
.
Swift 2.2:
public extension OptionSetType where RawValue : IntegerType {
func elements() -> AnySequence<Self> {
var remainingBits = self.rawValue
var bitMask: RawValue = 1
return AnySequence {
return AnyGenerator {
while remainingBits != 0 {
defer { bitMask = bitMask &* 2 }
if remainingBits & bitMask != 0 {
remainingBits = remainingBits & ~bitMask
return Self(rawValue: bitMask)
}
}
return nil
}
}
}
}
Пример использования:
let weekdays: WeekdaySet = [.Monday, .Tuesday]
for weekday in weekdays.elements() {
print(weekday)
}
// Output:
// WeekdaySet(rawValue: 2)
// WeekdaySet(rawValue: 4)
Swift 3:
public extension OptionSet where RawValue : Integer {
func elements() -> AnySequence<Self> {
var remainingBits = rawValue
var bitMask: RawValue = 1
return AnySequence {
return AnyIterator {
while remainingBits != 0 {
defer { bitMask = bitMask &* 2 }
if remainingBits & bitMask != 0 {
remainingBits = remainingBits & ~bitMask
return Self(rawValue: bitMask)
}
}
return nil
}
}
}
}
Swift 4:
public extension OptionSet where RawValue: FixedWidthInteger {
func elements() -> AnySequence<Self> {
var remainingBits = rawValue
var bitMask: RawValue = 1
return AnySequence {
return AnyIterator {
while remainingBits != 0 {
defer { bitMask = bitMask &* 2 }
if remainingBits & bitMask != 0 {
remainingBits = remainingBits & ~bitMask
return Self(rawValue: bitMask)
}
}
return nil
}
}
}
}