arrays - valor - que es enum
Obtenga todos los valores de enumeraciĆ³n como una matriz (12)
Para Swift 4.2 (Xcode 10) y posterior
Hay un protocolo
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)
}
Para Swift <4.2
No, no puede consultar una
enum
para saber qué valores contiene.
Ver
este artículo
Debe definir una matriz que enumere todos los valores que tiene.
Consulte también la
solución inteligente de
Frank Valbuena.
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)
}
Tengo la siguiente enumeración.
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
}
}
}
Necesito obtener todos los valores en bruto como una matriz de cadenas (como
["Pending", "On Hold", "Done"]
).
Agregué este método a la enumeración.
func toArray() -> [String] {
var n = 1
return Array(
GeneratorOf<EstimateItemStatus> {
return EstimateItemStatus(id: n++)!.description
}
)
}
Pero obtengo el siguiente error.
No se puede encontrar un inicializador para el tipo ''GeneratorOf'' que acepte una lista de argumentos del tipo ''(() -> _)''
No puedo entender cómo resolver esto. ¿Alguna ayuda? O dígame si hay una manera más fácil / mejor / más elegante de hacer esto.
Gracias.
Agregue el protocolo CaseIterable a la enumeración:
enum EstimateItemStatus: String, CaseIterable {
case pending = "Pending"
case onHold = "OnHold"
case done = "Done"
}
Uso:
let values: [String] = EstimateItemStatus.allCases.map { $0.rawValue }
//["Pending", "OnHold", "Done"]
Después de la inspiración de Sequence y horas de prueba y errores. Finalmente obtuve este cómodo y hermoso Swift 4 way en 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
}
}
Uso:
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)
}
Salida:
Pending
On Hold
Done
Encontré en alguna parte este código:
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
}
}
}
}
Utilizar:
enum YourEnum: EnumCollection { //code }
YourEnum.cases()
devolver la lista de casos de YourEnum
Hay otra forma que al menos es segura en tiempo de compilación:
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
}
}
Tenga en cuenta que esto funciona para cualquier tipo de enumeración (RawRepresentable o no) y también si agrega un nuevo caso, obtendrá un error del compilador que es bueno, ya que lo obligará a tener esto actualizado.
Para Swift 2
// Found http://.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))
}
Para usarlo:
arrayEnum(MyEnumClass.self)
Para obtener una lista con fines funcionales, use la expresión
EnumName.allCases
que devuelve una matriz, por ejemplo
EnumName.allCases.map{$0.rawValue}
le dará una lista de cadenas dado que
EnumName: String, CaseIterable
Nota: use
allCases
lugar de
AllCases()
.
Puedes usar
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)
}
Si su enumeración es incremental y está asociada con números, puede usar el rango de números que asigna a valores de enumeración, de esta manera:
// Swift 3
enum EstimateItemStatus: Int {
case pending = 1,
onHold
done
}
let estimateItemStatusValues: [EstimateItemStatus?] = (EstimateItemStatus.pending.rawValue...EstimateItemStatus.done.rawValue).map { EstimateItemStatus(rawValue: $0) }
Esto no funciona con enumeraciones asociadas con cadenas o cualquier otra cosa que no sean números, ¡pero funciona muy bien si ese es el caso!
Actualización para Swift 5
La solución más fácil que he encontrado es usar
.allCases
en una enumeración que extiende
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
en cualquier enumeración
CaseIterable
devolverá una
Collection
de ese elemento.
var myEnumArray = EstimateItemStatus.allCases
más información sobre CaseIterable
Swift 4.2
presenta un nuevo protocolo llamado
CaseIterable
enum Fruit : CaseIterable {
case apple , apricot , orange, lemon
}
que cuando se ajusta a, puede obtener una matriz de los casos de
enum
como este
for fruit in Fruit.allCases {
print("I like eating /(fruit).")
}
enum EstimateItemStatus: String, CaseIterable {
case pending = "Pending"
case onHold = "OnHold"
case done = "Done"
static var statusList: [String] {
return EstimateItemStatus.allCases.map { $0.rawValue }
}
}
["Pendiente", "En espera", "Listo"]