J'ai l'énumération suivante.
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
}
}
}
Je dois obtenir toutes les valeurs brutes sous forme de tableau de chaînes (comme suit: ["Pending", "On Hold", "Done"]
).
J'ai ajouté cette méthode à l'énumération.
func toArray() -> [String] {
var n = 1
return Array(
GeneratorOf<EstimateItemStatus> {
return EstimateItemStatus(id: n++)!.description
}
)
}
Mais je reçois l'erreur suivante.
Impossible de trouver un initialiseur de type 'GeneratorOf' acceptant une liste d'arguments de type '(() -> _)'
Je n'arrive pas à comprendre comment résoudre ce problème. De l'aide? Ou s'il vous plaît dites-moi s'il existe un moyen plus facile/meilleur/plus élégant de le faire.
Je vous remercie.
J'ai trouvé quelque part ce code:
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
}
}
}
}
Utilisation:
enum YourEnum: EnumCollection { //code }
YourEnum.cases()
retourne la liste des cas de YourEnum
Il existe un protocole 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)
}
Non, vous ne pouvez pas interroger une enum
pour connaître les valeurs qu'elle contient. Voir cet article . Vous devez définir un tableau qui liste toutes les valeurs que vous avez. Consultez également la solution clever 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)
}
Swift 4.2 introduit un nouveau protocole appelé CaseIterable
enum Fruit : CaseIterable {
case Apple , apricot , orange, lemon
}
que lorsque vous vous conformez, vous pouvez obtenir un tableau à partir des cas enum
comme celui-ci
for fruit in Fruit.allCases {
print("I like eating \(fruit).")
}
Il y a une autre façon de rester en sécurité au moment de la compilation:
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
}
}
Notez que cela fonctionne pour n'importe quel type d'énumération (RawRepresentable ou non) et que si vous ajoutez un nouveau cas, vous obtiendrez une erreur de compilation qui est bonne car cela vous obligera à l'actualiser.
Ajoutez CaseIterable protocol à l'énumération suivante:
enum EstimateItemStatus: String, CaseIterable {
case pending = "Pending"
case onHold = "OnHold"
case done = "Done"
}
Usage:
let values: [String] = EstimateItemStatus.allCases.map { $0.rawValue }
//["Pending", "OnHold", "Done"]
Pour 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))
}
Pour l'utiliser:
arrayEnum(MyEnumClass.self)
enum EstimateItemStatus: String, CaseIterable {
case pending = "Pending"
case onHold = "OnHold"
case done = "Done"
static var statusList: [String] {
return EstimateItemStatus.allCases.map { $0.rawValue }
}
}
["En attente", "OnHold", "Terminé"]
Après l’inspiration de Séquence et des heures d’essai, n erreurs. J'ai enfin eu cette belle et confortable Swift 4 way sur 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
}
}
Usage:
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)
}
Sortie:
Pending
On Hold
Done
Vous pouvez utiliser
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)
}
Mise à jour pour Swift 5
La solution la plus simple que j'ai trouvée consiste à utiliser .allCases
sur un enum qui étend 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
sur n'importe quel CaseIterable
enum retournera un Collection
de cet élément.
var myEnumArray = EstimateItemStatus.allCases
plus d'infos sur CaseIterable
Pour obtenir une liste à des fins fonctionnelles, utilisez l'expression EnumName.AllCases()
qui renvoie un tableau, par exemple.
EnumName.allCases.map{$0.rawValue}
vous donnera une liste de chaînes étant donné que EnumName: String, CaseIterable
Remarque: utilisez allCases
au lieu de AllCases()
.
Si votre énumération est incrémentielle et associée à des nombres, vous pouvez utiliser une plage de nombres que vous associez à des valeurs énumérées, comme suit:
// Swift 3
enum EstimateItemStatus: Int {
case pending = 1,
onHold
done
}
let estimateItemStatusValues: [EstimateItemStatus?] = (EstimateItemStatus.pending.rawValue...EstimateItemStatus.done.rawValue).map { EstimateItemStatus(rawValue: $0) }
Cela ne fonctionne pas vraiment avec des énumérations associées à des chaînes ou à autre chose que des nombres, mais cela fonctionne très bien si c'est le cas!