Получить все значения перечисления в виде массива
У меня есть следующее перечисление.
enum EstimateItemStatus: Printable {
case Pending
case OnHold
case Done
var description: String {
switch self {
case .Pending: return "Pending"
case .OnHold: return "On Hold"
case .Done: return "Done"
}
}
init?(id : Int) {
switch id {
case 1:
self = .Pending
case 2:
self = .OnHold
case 3:
self = .Done
default:
return nil
}
}
}
Мне нужно получить все необработанные значения в виде массива строк (например, ["Pending", "On Hold", "Done"]
).
Я добавил этот метод к перечислению.
func toArray() -> [String] {
var n = 1
return Array(
GeneratorOf<EstimateItemStatus> {
return EstimateItemStatus(id: n++)!.description
}
)
}
Но я получаю следующую ошибку.
Невозможно найти инициализатор для типа 'GeneratorOf', который принимает список аргументов типа '(() → _)'
Я не могу понять, как это решить. Любая помощь? Или, пожалуйста, скажите мне, есть ли более простой/лучший/более элегантный способ сделать это.
Спасибо.
Ответы
Ответ 1
Для Swift 4.2 (Xcode 10) и выше
Есть CaseIterable
протокол:
enum EstimateItemStatus: String, CaseIterable {
case pending = "Pending"
case onHold = "OnHold"
case done = "Done"
init?(id : Int) {
switch id {
case 1: self = .pending
case 2: self = .onHold
case 3: self = .done
default: return nil
}
}
}
for value in EstimateItemStatus.allCases {
print(value)
}
Для Swift <4.2
Нет, вы не можете запросить enum
какие значения оно содержит. Смотрите эту статью. Вы должны определить массив, в котором перечислены все значения, которые у вас есть. Также ознакомьтесь с умным решением Фрэнка Вальбуэны.
enum EstimateItemStatus: String {
case Pending = "Pending"
case OnHold = "OnHold"
case Done = "Done"
static let allValues = [Pending, OnHold, Done]
init?(id : Int) {
switch id {
case 1:
self = .Pending
case 2:
self = .OnHold
case 3:
self = .Done
default:
return nil
}
}
}
for value in EstimateItemStatus.allValues {
print(value)
}
Ответ 2
Swift 4.2 представляет новый протокол с именем CaseIterable
enum Fruit : CaseIterable {
case apple , apricot , orange, lemon
}
что когда вы соответствуете, вы можете получить массив из enum
случаев, как это
for fruit in Fruit.allCases {
print("I like eating \(fruit).")
}
Ответ 3
Другой способ, который по крайней мере безопасен во время компиляции:
enum MyEnum {
case case1
case case2
case case3
}
extension MyEnum {
static var allValues: [MyEnum] {
var allValues: [MyEnum] = []
switch (MyEnum.case1) {
case .case1: allValues.append(.case1); fallthrough
case .case2: allValues.append(.case2); fallthrough
case .case3: allValues.append(.case3)
}
return allValues
}
}
Обратите внимание, что это работает для любого типа перечисления (RawRepresentable или not), а также если вы добавляете новый случай, тогда вы получите ошибку компилятора, которая хороша, поскольку заставит вас обновить ее.
Ответ 4
Я нашел где-то этот код:
protocol EnumCollection : Hashable {}
extension EnumCollection {
static func cases() -> AnySequence<Self> {
typealias S = Self
return AnySequence { () -> AnyIterator<S> in
var raw = 0
return AnyIterator {
let current : Self = withUnsafePointer(to: &raw) { $0.withMemoryRebound(to: S.self, capacity: 1) { $0.pointee }
}
guard current.hashValue == raw else { return nil }
raw += 1
return current
}
}
}
}
Использование:
enum YourEnum: EnumCollection { //code }
YourEnum.cases()
вернуть список дел из YourEnum
Ответ 5
Добавьте CaseIterable протокол в enum:
enum EstimateItemStatus: String, CaseIterable {
case pending = "Pending"
case onHold = "OnHold"
case done = "Done"
}
Использование:
let values: [String] = EstimateItemStatus.allCases.map { $0.rawValue }
//["Pending", "OnHold", "Done"]
Ответ 6
Чтобы получить список для функциональных целей, используйте выражение EnumName.allCases
которое возвращает массив, например
EnumName.allCases.map{$0.rawValue}
даст вам список строк, учитывая, что EnumName: String, CaseIterable
Примечание: используйте allCases
вместо AllCases()
.
Ответ 7
Для Swift 2
// Found http://stackoverflow.com/questions/24007461/how-to-enumerate-an-enum-with-string-type
func iterateEnum<T where T: Hashable, T: RawRepresentable>(_: T.Type) -> AnyGenerator<T> {
var i = 0
return AnyGenerator {
let next = withUnsafePointer(&i) {
UnsafePointer<T>($0).memory
}
if next.hashValue == i {
i += 1
return next
} else {
return nil
}
}
}
func arrayEnum<T where T: Hashable, T: RawRepresentable>(type: T.Type) -> [T]{
return Array(iterateEnum(type))
}
Чтобы использовать его:
arrayEnum(MyEnumClass.self)
Ответ 8
После вдохновения от Sequence и нескольких часов попробуйте ошибки. Я наконец получил этот удобный и красивый способ Swift 4 на Xcode 9.1:
protocol EnumSequenceElement: Strideable {
var rawValue: Int { get }
init?(rawValue: Int)
}
extension EnumSequenceElement {
func distance(to other: Self) -> Int {
return other.rawValue - rawValue
}
func advanced(by n: Int) -> Self {
return Self(rawValue: n + rawValue) ?? self
}
}
struct EnumSequence<T: EnumSequenceElement>: Sequence, IteratorProtocol {
typealias Element = T
var current: Element? = T.init(rawValue: 0)
mutating func next() -> Element? {
defer {
if let current = current {
self.current = T.init(rawValue: current.rawValue + 1)
}
}
return current
}
}
Использование:
enum EstimateItemStatus: Int, EnumSequenceElement, CustomStringConvertible {
case Pending
case OnHold
case Done
var description: String {
switch self {
case .Pending:
return "Pending"
case .OnHold:
return "On Hold"
case .Done:
return "Done"
}
}
}
for status in EnumSequence<EstimateItemStatus>() {
print(status)
}
// Or by countable range iteration
for status: EstimateItemStatus in .Pending ... .Done {
print(status)
}
Выход:
Pending
On Hold
Done
Ответ 9
Ты можешь использовать
enum Status: Int{
case a
case b
case c
}
extension RawRepresentable where Self.RawValue == Int {
static var values: [Self] {
var values: [Self] = []
var index = 1
while let element = self.init(rawValue: index) {
values.append(element)
index += 1
}
return values
}
}
Status.values.forEach { (st) in
print(st)
}
Ответ 10
Если ваше перечисление является инкрементным и связано с числами, вы можете использовать диапазон чисел, который вы сопоставляете с значениями перечисления, например:
// Swift 3
enum EstimateItemStatus: Int {
case pending = 1,
onHold
done
}
let estimateItemStatusValues: [EstimateItemStatus?] = (EstimateItemStatus.pending.rawValue...EstimateItemStatus.done.rawValue).map { EstimateItemStatus(rawValue: $0) }
Это не работает с перечислениями, связанными со строками или чем-то другим, кроме чисел, но отлично работает, если это так!
Ответ 11
Подробнее
xCode 9.1, Swift 4
Решение
protocol EnumIterator {
static func getItem(at index: Int) -> Self?
}
extension Array where Element: EnumIterator {
static var all: [Element] {
var result = [Element]()
var index = 0
while true {
if let item = Element.getItem(at: index) {
result.append(item)
index += 1
} else {
break
}
}
return result
}
}
Использование
перечисление
enum Enum: EnumIterator {
case val1, val2, val3
static func getItem(at index: Int) -> Enum? {
switch index {
case 0: return .val1
case 1: return .val2
case 2: return .val3
default: return nil
}
}
}
Массив со всеми значениями перечисления
let array = [Enum].all
Полный образец
Не забудьте вставить здесь код решения
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let array1 = [Enum].all
print("\(array1)")
let array2 = [StringEnum].all
print("\(array2)")
}
}
enum Enum: EnumIterator {
case val1, val2, val3
static func getItem(at index: Int) -> Enum? {
switch index {
case 0: return .val1
case 1: return .val2
case 2: return .val3
default: return nil
}
}
}
enum StringEnum: String, EnumIterator {
case str1="str1", str2="str2", str3="str3"
static func getItem(at index: Int) -> StringEnum? {
switch index {
case 0: return .str1
case 1: return .str2
case 2: return .str3
default: return nil
}
}
}
Результаты
![введите описание изображения здесь]()
![введите описание изображения здесь]()
![введите описание изображения здесь]()
Ответ 12
Обновление для Swift 5
.allCases
решение, которое я нашел, - это использовать .allCases
для перечисления, расширяющего CaseIterable
enum EstimateItemStatus: CaseIterable {
case Pending
case OnHold
case Done
var description: String {
switch self {
case .Pending: return "Pending"
case .OnHold: return "On Hold"
case .Done: return "Done"
}
}
init?(id : Int) {
switch id {
case 1:
self = .Pending
case 2:
self = .OnHold
case 3:
self = .Done
default:
return nil
}
}
}
.allCases
любого перечисления CaseIterable
возвращает Collection
этого элемента.
var myEnumArray = EstimateItemStatus.allCases
больше информации о CaseIterable
Ответ 13
enum EstimateItemStatus: String, CaseIterable {
case pending = "Pending"
case onHold = "OnHold"
case done = "Done"
static var statusList: [String] {
return EstimateItemStatus.allCases.map { $0.rawValue }
}
}
["Ожидание", "OnHold", "Готово"]