Mam następujący wyliczenie.
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
}
}
}
Muszę pobrać wszystkie surowe wartości jako tablicę ciągów (tak jak to ["Pending", "On Hold", "Done"]
).
Dodałem tę metodę do wyliczenia.
func toArray() -> [String] {
var n = 1
return Array(
GeneratorOf<EstimateItemStatus> {
return EstimateItemStatus(id: n++)!.description
}
)
}
Ale pojawia się następujący błąd.
Nie można znaleźć inicjatora dla typu „GeneratorOf”, który akceptuje listę argumentów typu „(() -> _)”
Czy jest na to łatwiejszy, lepszy lub bardziej elegancki sposób?
Odpowiedzi:
Dla Swift 4.2 (Xcode 10) i nowszych
Jest
CaseIterable
protokół: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) }
Dla Swift <4,2
Nie, nie możesz zapytać,
enum
jakie wartości zawiera. Zobacz ten artykuł . Musisz zdefiniować tablicę zawierającą wszystkie posiadane wartości. Sprawdź również rozwiązanie Franka Valbueny w artykule „ Jak uzyskać wszystkie wartości wyliczenia jako tablicę ”.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) }
źródło
Swift 4.2 wprowadza nowy protokół o nazwie
CaseIterable
enum Fruit : CaseIterable { case apple , apricot , orange, lemon }
że kiedy się dostosujesz, możesz uzyskać tablicę z takich
enum
przypadkówfor fruit in Fruit.allCases { print("I like eating \(fruit).") }
źródło
Dodaj protokół CaseIterable do wyliczenia:
enum EstimateItemStatus: String, CaseIterable { case pending = "Pending" case onHold = "OnHold" case done = "Done" }
Stosowanie:
let values: [String] = EstimateItemStatus.allCases.map { $0.rawValue } //["Pending", "OnHold", "Done"]
źródło
Jest jeszcze jeden sposób, który przynajmniej jest bezpieczny w czasie kompilacji:
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 } }
Zauważ, że działa to dla każdego typu wyliczenia (RawRepresentable lub nie), a także jeśli dodasz nowy przypadek, otrzymasz błąd kompilatora, który jest dobry, ponieważ zmusi Cię do zaktualizowania tego.
źródło
Znalazłem gdzieś ten kod:
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 } } } }
Posługiwać się:
enum YourEnum: EnumCollection { //code } YourEnum.cases()
lista zwrotów spraw z YourEnum
źródło
enum EstimateItemStatus: String, CaseIterable { case pending = "Pending" case onHold = "OnHold" case done = "Done" static var statusList: [String] { return EstimateItemStatus.allCases.map { $0.rawValue } } }
[„Oczekujące”, „Wstrzymane”, „Gotowe”]
źródło
Aby uzyskać listę do celów funkcjonalnych, użyj wyrażenia,
EnumName.allCases
które zwraca tablicę npEnumName.allCases.map{$0.rawValue}
poda ci listę ciągów znaków, które to podano
EnumName: String, CaseIterable
Uwaga: użyj
allCases
zamiastAllCases()
.źródło
Aktualizacja dla Swift 5
Najłatwiejszym rozwiązaniem, jakie znalazłem, jest użycie
.allCases
na wyliczeniu, które rozszerzaCaseIterable
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
na każdymCaseIterable
wyliczeniu zwróci aCollection
z tego elementu.var myEnumArray = EstimateItemStatus.allCases
więcej informacji o CaseIterable
źródło
case OnHold = "On Hold"
I stanie się on wartością surową dla każdego.Dla 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)) }
Aby z niego skorzystać:
arrayEnum(MyEnumClass.self)
źródło
hashValue
być0..n
?Po inspiracji z Sekwencji i godzinach prób n błędów. W końcu dostałem ten wygodny i piękny Swift 4 Way na 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 } }
Stosowanie:
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) }
Wynik:
Pending On Hold Done
źródło
Możesz użyć
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) }
źródło
Jeśli wyliczenie jest przyrostowe i skojarzone z liczbami, możesz użyć zakresu liczb, które są mapowane na wartości wyliczeniowe, na przykład:
// Swift 3 enum EstimateItemStatus: Int { case pending = 1, onHold done } let estimateItemStatusValues: [EstimateItemStatus?] = (EstimateItemStatus.pending.rawValue...EstimateItemStatus.done.rawValue).map { EstimateItemStatus(rawValue: $0) }
To nie działa w przypadku wyliczeń skojarzonych z ciągami znaków lub czymkolwiek innym niż liczby, ale działa świetnie, jeśli tak jest!
źródło
Rozszerzenie na wyliczenie, aby utworzyć allValues.
extension RawRepresentable where Self: CaseIterable { static var allValues: [Self.RawValue] { return self.allCases.map { $0.rawValue} } }
źródło