У меня есть следующее перечисление.
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, который принимает список аргументов типа (() -> _) '
Есть ли способ сделать это проще, лучше или элегантнее?
Ответы:
Для 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) }
источник
Swift 4.2 представляет новый протокол под названием
CaseIterable
enum Fruit : CaseIterable { case apple , apricot , orange, lemon }
что, если вы соответствуете, вы можете получить массив из таких
enum
случаевfor fruit in Fruit.allCases { print("I like eating \(fruit).") }
источник
Добавьте протокол CaseIterable в перечисление:
enum EstimateItemStatus: String, CaseIterable { case pending = "Pending" case onHold = "OnHold" case done = "Done" }
Применение:
let values: [String] = EstimateItemStatus.allCases.map { $0.rawValue } //["Pending", "OnHold", "Done"]
источник
Есть еще один способ, безопасный по крайней мере во время компиляции:
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 или нет), а также, если вы добавите новый кейс, вы получите ошибку компилятора, которая хороша, поскольку заставит вас обновить ее.
источник
Я где-то нашел этот код:
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
источник
enum EstimateItemStatus: String, CaseIterable { case pending = "Pending" case onHold = "OnHold" case done = "Done" static var statusList: [String] { return EstimateItemStatus.allCases.map { $0.rawValue } } }
[«В ожидании», «OnHold», «Готово»]
источник
Чтобы получить список для функциональных целей, используйте выражение,
EnumName.allCases
которое возвращает массив, напримерEnumName.allCases.map{$0.rawValue}
предоставит вам список строк, учитывая, что
EnumName: String, CaseIterable
Примечание: используйте
allCases
вместоAllCases()
.источник
Обновление для Swift 5
Самое простое решение, которое я нашел, - использовать
.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
перечислении вернет aCollection
этого элемента.var myEnumArray = EstimateItemStatus.allCases
больше информации о CaseIterable
источник
case OnHold = "On Hold"
и это станет исходным значением для каждого.Для 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)
источник
hashValue
должны быть0..n
?После вдохновения от 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
источник
Ты можешь использовать
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) }
источник
Если ваше перечисление является инкрементным и связано с числами, вы можете использовать диапазон чисел, который вы сопоставляете со значениями перечисления, например:
// Swift 3 enum EstimateItemStatus: Int { case pending = 1, onHold done } let estimateItemStatusValues: [EstimateItemStatus?] = (EstimateItemStatus.pending.rawValue...EstimateItemStatus.done.rawValue).map { EstimateItemStatus(rawValue: $0) }
Это не совсем работает с перечислениями, связанными со строками или чем-либо, кроме чисел, но отлично работает, если это так!
источник
Расширение перечисления для создания allValues.
extension RawRepresentable where Self: CaseIterable { static var allValues: [Self.RawValue] { return self.allCases.map { $0.rawValue} } }
источник