web-dev-qa-db-fra.com

Obtenir toutes les valeurs enum sous forme de tableau

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.

49
Isuru

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

10
Daniel Kuta

Pour Swift 4.2 (Xcode 10) et ultérieur

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)
}

Pour Swift <4.2

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)
}
72
Code Different

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).")
}
19
Sh_Khan

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. 

13
Frank Valbuena

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"]
6
maxwell

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)
2
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é"]

2
Vladimir Pchelyakov

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
1
mclam

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

0

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().

0
Archy Will He

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!

0
Ben Patch