Comment obtenir le décompte d'une énumération Swift?

Réponses:

173

Depuis Swift 4.2 (Xcode 10), vous pouvez déclarer la conformité au CaseIterableprotocole, cela fonctionne pour toutes les énumérations sans valeurs associées:

enum Stuff: CaseIterable {
    case first
    case second
    case third
    case forth
}

Le nombre de cas est maintenant obtenu simplement avec

print(Stuff.allCases.count) // 4

Pour plus d'informations, consultez

Martin R
la source
1
Dans la dernière version de swift, son erreur de lancement "Type 'DAFFlow' n'est pas conforme au protocole 'RawRepresentable'". Pourquoi est-ce que je suis obligé de suivre cela? Une idée?
Satyam
@Satyam: Qu'est-ce que DAFFlow?
Martin R
désolé j'ai oublié de mentionner que "DAFFlow 'est une simple énumération qui n'hérite d'aucun autre protocole.
Satyam
1
C'est la meilleure solution, mais juste pour plus de clarté - les développeurs Apple ne pourront vraiment commencer à l'utiliser qu'une fois que Xcode 10 (et donc Swift 4.2) sortira de la version bêta (donc probablement vers le 14 septembre 2018).
JosephH
1
@DaniSpringer: Vous trouverez les détails sanglants sur github.com/apple/swift-evolution/blob/master/proposals/… . Mais généralement, vous n'avez pas besoin de ce type explicitement, en raison de l'inférence de type automatique du compilateur.
Martin R
143

J'ai un article de blog qui va plus en détail à ce sujet, mais tant que le type brut de votre énumération est un entier, vous pouvez ajouter un décompte de cette façon:

enum Reindeer: Int {
    case Dasher, Dancer, Prancer, Vixen, Comet, Cupid, Donner, Blitzen
    case Rudolph

    static let count: Int = {
        var max: Int = 0
        while let _ = Reindeer(rawValue: max) { max += 1 }
        return max
    }()
}
Nate Cook
la source
16
Bien que cela soit agréable car vous n'avez pas besoin de coder en dur une valeur, cela instanciera chaque valeur d'énumération à chaque fois qu'elle sera appelée. C'est O (n) au lieu de O (1). :(
Code Commander
4
C'est une bonne solution pour les Int contigus. Je préfère une légère modification. Transformez la propriété static count en une méthode statique countCases () et affectez-la à une constante statique caseCount qui est paresseuse et améliore les performances avec des appels répétés.
Tom Pelaia
2
@ShamsAhmed: conversion de la var calculée en une variable statique.
Nate Cook
3
Et si vous manquez une valeur dans l'énumération? par exemple case A=1, B=3?
Sasho
2
Il y a 2 hypothèses en plus d' enumavoir une Intvaleur brute que vous avez oublié de mentionner: les énumérations Swift avec des valeurs brutes Int n'ont pas à commencer à partir de 0 (même si c'est le comportement par défaut) et leurs valeurs brutes peuvent être arbitraires, elles n'ont pas pour incrémenter de 1 (même si c'est le comportement par défaut).
Dávid Pásztor
90

Mise à jour Xcode 10

Adoptez le CaseIterableprotocole dans l'énumération, il fournit une allCasespropriété statique qui contient tous les cas d'énumération sous forme de fichier Collection. Utilisez simplement sa countpropriété pour savoir combien de cas l'énumération a.

Voir la réponse de Martin pour un exemple (et voter pour ses réponses plutôt que les miennes)


avertissement : la méthode ci-dessous ne semble plus fonctionner.

Je ne connais aucune méthode générique pour compter le nombre de cas d'énumération. J'ai cependant remarqué que la hashValuepropriété des cas enum est incrémentale, à partir de zéro, et avec l'ordre déterminé par l'ordre dans lequel les cas sont déclarés. Ainsi, le hachage de la dernière énumération plus un correspond au nombre de cas.

Par exemple avec cette énumération:

enum Test {
    case ONE
    case TWO
    case THREE
    case FOUR

    static var count: Int { return Test.FOUR.hashValue + 1}
}

count renvoie 4.

Je ne peux pas dire si c'est une règle ou si cela changera un jour, alors utilisez à vos risques et périls :)

Antonio
la source
48
Vivez par la fonctionnalité non documentée, mourez par la fonctionnalité non documentée. Je l'aime!
Nate Cook
9
Nous ne devrions pas vraiment compter sur hashValuesces choses; tout ce que nous savons, c'est qu'il s'agit d'une valeur unique aléatoire - pourrait changer très facilement à l'avenir en fonction de certains détails d'implémentation du compilateur; mais dans l'ensemble, le manque de fonctionnalité de comptage intégrée est inquiétant.
Zorayr
16
Si cela ne vous dérange pas de définir explicitement case ONE = 0, vous pouvez alors remplacer hashValuepar rawValue.
Kevin Qi
3
le problème ici est l'utilisation d'une propriété non documentée de hashValue, donc ma suggestion est d'utiliser une propriété documentée de rawValue.
Kevin Qi
7
Vous avez déjà codé en dur le fait de quelle constante est la valeur la plus élevée, mieux et plus sûr d'utiliser simplement quelque chose comme static var count = 4plutôt que de laisser votre destin dans le sort des futures implémentations de Swift
Dale
72

Je définis un protocole réutilisable qui effectue automatiquement le décompte des cas en fonction de l'approche publiée par Nate Cook.

protocol CaseCountable {
    static var caseCount: Int { get }
}

extension CaseCountable where Self: RawRepresentable, Self.RawValue == Int {
    internal static var caseCount: Int {
        var count = 0
        while let _ = Self(rawValue: count) {
            count += 1
        }
        return count
    }
}

Ensuite, je peux réutiliser ce protocole par exemple comme suit:

enum Planet : Int, CaseCountable {
    case Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
}
//..
print(Planet.caseCount)
Tom Pelaia
la source
1
Agréable et élégant, devrait être la réponse acceptée à
mon humble avis
1
peut - être qu'il est préférable de changer count++de count+=1car la ++notation sera supprimée dans Swift 3
aladin
1
ne pourrait-on pas faire la même chose avec seulement static var caseCount: Int { get }? pourquoi le besoin de l ' static func?
pxpgraphics
Et si vous manquez une valeur dans l'énumération? par exemple case A=1, B=3?
Sasho
1
@Sasho, alors ça ne marchera pas. Cela nécessite que vos cas commencent à 0et ne présentent aucune lacune.
NRitH
35

Créer un tableau statique allValues ​​comme indiqué dans cette réponse

enum ProductCategory : String {
     case Washers = "washers", Dryers = "dryers", Toasters = "toasters"

     static let allValues = [Washers, Dryers, Toasters]
}

...

let count = ProductCategory.allValues.count

Ceci est également utile lorsque vous souhaitez énumérer les valeurs et fonctionne pour tous les types Enum

David72
la source
Bien que pas aussi élégant que la solution d'extensions et très manuel, je pense que c'est le plus utile car il offre beaucoup plus que de compter. Il vous donne l'ordre des valeurs et une liste de toutes les valeurs.
Nader Eloshaiker
2
Vous pouvez également ajouter le nombre à l'énumération en faisant static let count = allValues.count. Ensuite, vous pouvez rendre le allValuesprivé si vous le souhaitez.
ThomasW
15

Si l'implémentation n'a rien contre l'utilisation d' Counténumérations entières, vous pouvez ajouter une valeur de membre supplémentaire appelée pour représenter le nombre de membres dans l'énumération - voir l'exemple ci-dessous:

enum TableViewSections : Int {
  case Watchlist
  case AddButton
  case Count
}

Vous pouvez maintenant obtenir le nombre de membres dans l'énumération en appelant, TableViewSections.Count.rawValuece qui renverra 2 pour l'exemple ci-dessus.

Lorsque vous gérez l'énumération dans une instruction switch, assurez-vous de lancer un échec d'assertion lorsque vous rencontrez le Countmembre là où vous ne vous attendez pas:

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  let currentSection: TableViewSections = TableViewSections.init(rawValue:section)!
  switch(currentSection) {
  case .Watchlist:
    return watchlist.count
  case .AddButton:
    return 1
  case .Count:
    assert(false, "Invalid table view section!")
  }
}
Zorayr
la source
J'aime cette solution car elle change automatiquement le décompte lors de l'ajout de valeurs d'énumération supplémentaires. Cependant, gardez à l'esprit que cela ne fonctionne que lorsque les rawValues ​​de l'énumération commencent par 0.
joern
2
D'accord, il y a deux restrictions: doit être une énumération entière et doit commencer à zéro et continuer de manière incrémentielle.
Zorayr
3
Je pensais que tout l'intérêt des énumérations plus puissantes de Swift était que nous n'aurions pas à utiliser les mêmes hacks que nous avons utilisés dans Objective-C: /
pkamb
14

Ce type de fonction est capable de renvoyer le décompte de votre énumération.

Swift 2 :

func enumCount<T: Hashable>(_: T.Type) -> Int {
    var i = 1
    while (withUnsafePointer(&i) { UnsafePointer<T>($0).memory }).hashValue != 0 {
        i += 1
    }
    return i
}

Swift 3 :

func enumCount<T: Hashable>(_: T.Type) -> Int {
   var i = 1
   while (withUnsafePointer(to: &i, {
      return $0.withMemoryRebound(to: T.self, capacity: 1, { return $0.pointee })
   }).hashValue != 0) {
      i += 1
   }
      return i
   }
Matthieu Riegler
la source
3
Cela ne fonctionne plus pour Swift 3. Essayer de trouver la bonne implémentation, mais venir vide
Cody Winton
Ce sera très difficile à déboguer si l'adresse mémoire immédiatement adjacente à la fin du enumest également Hashable du même type.
NRitH
10

Énumération de chaîne avec index

enum eEventTabType : String {
    case Search     = "SEARCH"
    case Inbox      = "INBOX"
    case Accepted   = "ACCEPTED"
    case Saved      = "SAVED"
    case Declined   = "DECLINED"
    case Organized  = "ORGANIZED"

    static let allValues = [Search, Inbox, Accepted, Saved, Declined, Organized]
    var index : Int {
       return eEventTabType.allValues.indexOf(self)!
    }
}

compter : eEventTabType.allValues.count

index: objeEventTabType.index

Prendre plaisir :)

Kalpesh jetani
la source
10

Oh hé tout le monde, qu'en est-il des tests unitaires?

func testEnumCountIsEqualToNumberOfItemsInEnum() {

    var max: Int = 0
    while let _ = Test(rawValue: max) { max += 1 }

    XCTAssert(max == Test.count)
}

Ceci combiné avec la solution d'Antonio:

enum Test {

    case one
    case two
    case three
    case four

    static var count: Int { return Test.four.hashValue + 1}
}

dans le code principal vous donne O (1) plus vous obtenez un test qui échoue si quelqu'un ajoute un cas d'énumération fiveet ne met pas à jour l'implémentation de count.

construction réussie
la source
7

Cette fonction repose sur 2 comportements courants non documentés (Swift 1.1) enum:

  • La disposition de la mémoire de enumn'est qu'un index de case. Si le nombre de cas est compris entre 2 et 256, c'estUInt8 .
  • Si le enumbit a été converti à partir d'un index de cas non valide , il hashValueest0

Alors utilisez à vos risques et périls :)

func enumCaseCount<T:Hashable>(t:T.Type) -> Int {
    switch sizeof(t) {
    case 0:
        return 1
    case 1:
        for i in 2..<256 {
            if unsafeBitCast(UInt8(i), t).hashValue == 0 {
                return i
            }
        }
        return 256
    case 2:
        for i in 257..<65536 {
            if unsafeBitCast(UInt16(i), t).hashValue == 0 {
                return i
            }
        }
        return 65536
    default:
        fatalError("too many")
    }
}

Usage:

enum Foo:String {
    case C000 = "foo"
    case C001 = "bar"
    case C002 = "baz"
}
enumCaseCount(Foo) // -> 3
Rintaro
la source
Dans la version et l'application adhoc CRASH
HotJard
Cela fonctionne dans le simulateur mais pas sur un vrai périphérique 64 bits.
Daniel Nord
5

J'ai écrit une extension simple qui donne à toutes les énumérations où la valeur brute est un entier une countpropriété:

extension RawRepresentable where RawValue: IntegerType {
    static var count: Int {
        var i: RawValue = 0
        while let _ = Self(rawValue: i) {
            i = i.successor()
        }
        return Int(i.toIntMax())
    }
}

Malheureusement, il donne la countpropriété OptionSetTypelà où cela ne fonctionnera pas correctement, voici donc une autre version qui nécessite une conformité explicite au CaseCountableprotocole pour toute énumération des cas que vous souhaitez compter:

protocol CaseCountable: RawRepresentable {}
extension CaseCountable where RawValue: IntegerType {
    static var count: Int {
        var i: RawValue = 0
        while let _ = Self(rawValue: i) {
            i = i.successor()
        }
        return Int(i.toIntMax())
    }
}

C'est très similaire à l'approche publiée par Tom Pelaia, mais fonctionne avec tous les types entiers.

bzz
la source
4

Bien sûr, ce n'est pas dynamique mais pour de nombreuses utilisations, vous pouvez vous en tirer avec une variable statique ajoutée à votre Enum

static var count: Int{ return 7 }

puis utilisez-le comme EnumName.count

Ian Dundas
la source
3
enum EnumNameType: Int {
    case first
    case second
    case third

    static var count: Int { return EnumNameType.third.rawValue + 1 }
}

print(EnumNameType.count) //3

OU

enum EnumNameType: Int {
    case first
    case second
    case third
    case count
}

print(EnumNameType.count.rawValue) //3

* Sur Swift 4.2 (Xcode 10) peut utiliser:

enum EnumNameType: CaseIterable {
    case first
    case second
    case third
}

print(EnumNameType.allCases.count) //3
Lê Cường
la source
2

Pour mon cas d'utilisation, dans une base de code où plusieurs personnes pourraient ajouter des clés à une énumération, et ces cas devraient tous être disponibles dans la propriété allKeys, il est important que allKeys soit validé par rapport aux clés de l'énumération. Ceci afin d'éviter que quelqu'un oublie d'ajouter sa clé à la liste de toutes les clés.Faire correspondre le nombre du tableau allKeys (d'abord créé comme un ensemble pour éviter les dupes) avec le nombre de clés dans l'énumération garantit qu'elles sont toutes présentes.

Certaines des réponses ci-dessus montrent la manière d'y parvenir dans Swift 2, mais aucune ne fonctionne dans Swift 3 . Voici la version formatée de Swift 3 :

static func enumCount<T: Hashable>(_ t: T.Type) -> Int {
    var i = 1
    while (withUnsafePointer(to: &i) {
      $0.withMemoryRebound(to:t.self, capacity:1) { $0.pointee.hashValue != 0 }
    }) {
      i += 1
    }
    return i
}

static var allKeys: [YourEnumTypeHere] {
    var enumSize = enumCount(YourEnumTypeHere.self)

    let keys: Set<YourEnumTypeHere> = [.all, .your, .cases, .here]
    guard keys.count == enumSize else {
       fatalError("Missmatch between allKeys(\(keys.count)) and actual keys(\(enumSize)) in enum.")
    }
    return Array(keys)
}

En fonction de votre cas d'utilisation, vous voudrez peut-être simplement exécuter le test en développement pour éviter la surcharge liée à l'utilisation de allKeys à chaque demande

Chris Mitchelmore
la source
2

Pourquoi rendez-vous tout cela si complexe? Le compteur SIMPLEST de l'énumération Int consiste à ajouter:

case Count

À la fin. Et ... alto - maintenant vous avez le décompte - rapide et simple

Dimitar Marinov
la source
1
Cela a) ajoute un cas d'énumération superflu et b) ne fonctionnera pas si le type brut de l'énumération est autre chose que Int.
Robert Atkins
Ce n'est en fait pas une mauvaise réponse. Comme la réponse de @Tom Pelaia ci-dessus, cependant, il faut que les valeurs brutes commencent à 0et qu'il n'y ait pas de lacunes dans la séquence.
NRitH
1

Si vous ne voulez pas baser votre code dans la dernière énumération, vous pouvez créer cette fonction dans votre énumération.

func getNumberOfItems() -> Int {
    var i:Int = 0
    var exit:Bool = false
    while !exit {
        if let menuIndex = MenuIndex(rawValue: i) {
            i++
        }else{
            exit = true
        }
    }
    return i
}
Gabriel Araujo
la source
1

Une version Swift 3 fonctionnant avec Intles énumérations de types:

protocol CaseCountable: RawRepresentable {}
extension CaseCountable where RawValue == Int {
    static var count: RawValue {
        var i: RawValue = 0
        while let _ = Self(rawValue: i) { i += 1 }
        return i
    }
}

Crédits: Basé sur les réponses de bzz et Nate Cook.

Generic IntegerType(dans Swift 3 renommé en Integer) n'est pas pris en charge, car il s'agit d'un type générique fortement fragmenté qui manque de nombreuses fonctions. successorn'est plus disponible avec Swift 3.

Sachez que le commentaire de Code Commander à la réponse de Nate Cooks est toujours valide:

Bien que cela soit agréable car vous n'avez pas besoin de coder en dur une valeur, cela instanciera chaque valeur enum à chaque fois qu'elle est appelée. C'est O (n) au lieu de O (1).

Pour autant que je sache, il n'y a actuellement aucune solution de contournement lors de l'utilisation de cette extension de protocole (et de la non-implémentation dans chaque énumération comme Nate Cook l'a fait) en raison des propriétés stockées statiques qui ne sont pas prises en charge dans les types génériques.

Quoi qu'il en soit, pour les petites énumérations, cela ne devrait pas poser de problème. Un cas d'utilisation typique serait le section.countpour UITableViewscomme déjà mentionné par Zorayr.

Frederik Winkelsdorf
la source
1

En étendant la réponse de Matthieu Riegler, il s'agit d'une solution pour Swift 3 qui ne nécessite pas l'utilisation de génériques, et peut être facilement appelée en utilisant le type enum avec EnumType.elementsCount:

extension RawRepresentable where Self: Hashable {

    // Returns the number of elements in a RawRepresentable data structure
    static var elementsCount: Int {
        var i = 1
        while (withUnsafePointer(to: &i, {
            return $0.withMemoryRebound(to: self, capacity: 1, { return 
                   $0.pointee })
        }).hashValue != 0) {
            i += 1
        }
        return i
}
matsoftware
la source
0

J'ai résolu ce problème pour moi-même en créant un protocole (EnumIntArray) et une fonction utilitaire globale (enumIntArray) qui facilitent l'ajout d'une variable "All" à n'importe quelle énumération (en utilisant swift 1.2). La variable "all" contiendra un tableau de tous les éléments de l'énumération afin que vous puissiez utiliser all.count pour le nombre

Cela ne fonctionne qu'avec les énumérations qui utilisent des valeurs brutes de type Int, mais peut-être peut-il fournir une certaine inspiration pour d'autres types.

Il aborde également les problèmes de «manque de numérotation» et de «temps excessif pour itérer» que j'ai lus ci-dessus et ailleurs.

L'idée est d'ajouter le protocole EnumIntArray à votre enum, puis de définir une variable statique «all» en appelant la fonction enumIntArray et de lui fournir le premier élément (et le dernier s'il y a des lacunes dans la numérotation).

Étant donné que la variable statique n'est initialisée qu'une seule fois, la surcharge liée au passage de toutes les valeurs brutes ne touche votre programme qu'une seule fois.

exemple (sans lacunes):

enum Animals:Int, EnumIntArray
{ 
  case Cat=1, Dog, Rabbit, Chicken, Cow
  static var all = enumIntArray(Animals.Cat)
}

exemple (avec des lacunes):

enum Animals:Int, EnumIntArray
{ 
  case Cat    = 1,  Dog, 
  case Rabbit = 10, Chicken, Cow
  static var all = enumIntArray(Animals.Cat, Animals.Cow)
}

Voici le code qui l'implémente:

protocol EnumIntArray
{
   init?(rawValue:Int)
   var rawValue:Int { get }
}

func enumIntArray<T:EnumIntArray>(firstValue:T, _ lastValue:T? = nil) -> [T]
{
   var result:[T] = []
   var rawValue   = firstValue.rawValue
   while true
   { 
     if let enumValue = T(rawValue:rawValue++) 
     { result.append(enumValue) }
     else if lastValue == nil                     
     { break }

     if lastValue != nil
     && rawValue  >  lastValue!.rawValue          
     { break }
   } 
   return result   
}
Alain T.
la source
0

Ou vous pouvez simplement définir l' _countextérieur de l'énumération et l'attacher de manière statique:

let _count: Int = {
    var max: Int = 0
    while let _ = EnumName(rawValue: max) { max += 1 }
    return max
}()

enum EnumName: Int {
    case val0 = 0
    case val1
    static let count = _count
}

De cette façon, quel que soit le nombre d'énumérations que vous créez, il ne sera créé qu'une seule fois.

(supprimez cette réponse si staticc'est le cas)

À
la source
0

La méthode suivante provient de CoreKit et est similaire aux réponses suggérées par d'autres. Cela fonctionne avec Swift 4.

public protocol EnumCollection: Hashable {
    static func cases() -> AnySequence<Self>
    static var allValues: [Self] { get }
}

public extension EnumCollection {

    public static func cases() -> AnySequence<Self> {
        return AnySequence { () -> AnyIterator<Self> in
            var raw = 0
            return AnyIterator {
                let current: Self = withUnsafePointer(to: &raw) { $0.withMemoryRebound(to: self, capacity: 1) { $0.pointee } }
                guard current.hashValue == raw else {
                    return nil
                }
                raw += 1
                return current
            }
        }
    }

    public static var allValues: [Self] {
        return Array(self.cases())
    }
}

enum Weekdays: String, EnumCollection {
    case sunday, monday, tuesday, wednesday, thursday, friday, saturday
}

Ensuite, il vous suffit d'appeler Weekdays.allValues.count.

ThomasW
la source
0
enum WeekDays : String , CaseIterable
{
  case monday = "Mon"
  case tuesday = "Tue"
  case wednesday = "Wed"
  case thursday = "Thu"
  case friday = "Fri"
  case saturday = "Sat"
  case sunday = "Sun"
}

var weekdays = WeekDays.AllCases()

print("\(weekdays.count)")
Nupur Sharma
la source
-1
struct HashableSequence<T: Hashable>: SequenceType {
    func generate() -> AnyGenerator<T> {
        var i = 0
        return AnyGenerator {
            let next = withUnsafePointer(&i) { UnsafePointer<T>($0).memory }
            if next.hashValue == i {
                i += 1
                return next
            }
            return nil
        }
    }
}

extension Hashable {
    static func enumCases() -> Array<Self> {
        return Array(HashableSequence())
    }

    static var enumCount: Int {
        return enumCases().enumCount
    }
}

enum E {
    case A
    case B
    case C
}

E.enumCases() // [A, B, C]
E.enumCount   //  3

mais soyez prudent avec l'utilisation sur les types non-enum. Une solution de contournement pourrait être:

struct HashableSequence<T: Hashable>: SequenceType {
    func generate() -> AnyGenerator<T> {
        var i = 0
        return AnyGenerator {
            guard sizeof(T) == 1 else {
                return nil
            }
            let next = withUnsafePointer(&i) { UnsafePointer<T>($0).memory }
            if next.hashValue == i {
                i += 1
                return next
            }

            return nil
        }
    }
}

extension Hashable {
    static func enumCases() -> Array<Self> {
        return Array(HashableSequence())
    }

    static var enumCount: Int {
        return enumCases().count
    }
}

enum E {
    case A
    case B
    case C
}

Bool.enumCases()   // [false, true]
Bool.enumCount     // 2
String.enumCases() // []
String.enumCount   // 0
Int.enumCases()    // []
Int.enumCount      // 0
E.enumCases()      // [A, B, C]
E.enumCount        // 4
JMI
la source
-1

Il peut utiliser une constante statique qui contient la dernière valeur de l'énumération plus un.

enum Color : Int {
    case  Red, Orange, Yellow, Green, Cyan, Blue, Purple

    static let count: Int = Color.Purple.rawValue + 1

    func toUIColor() -> UIColor{
        switch self {
            case .Red:
                return UIColor.redColor()
            case .Orange:
                return UIColor.orangeColor()
            case .Yellow:
                return UIColor.yellowColor()
            case .Green:
                return UIColor.greenColor()
            case .Cyan:
                return UIColor.cyanColor()
            case .Blue:
                return UIColor.blueColor()
            case .Purple:
                return UIColor.redColor()
        }
    }
}
93sauu
la source
-3

C'est mineur, mais je pense qu'une meilleure solution O (1) serait la suivante ( UNIQUEMENT si votre énumération Intcommence à x, etc.):

enum Test : Int {
    case ONE = 1
    case TWO
    case THREE
    case FOUR // if you later need to add additional enums add above COUNT so COUNT is always the last enum value 
    case COUNT

    static var count: Int { return Test.COUNT.rawValue } // note if your enum starts at 0, some other number, etc. you'll need to add on to the raw value the differential 
}

La réponse actuellement sélectionnée, je crois toujours, est la meilleure réponse pour toutes les énumérations, sauf si vous travaillez avec, Intje recommande cette solution.

Drmorgan
la source
3
Ajouter une valeur à votre énumération qui ne représente pas réellement le type de l'énumération est une mauvaise odeur de code. J'ai du mal à justifier l'inclusion d'un "TOUT" ou d'un "AUCUN" même si cela peut parfois être tentant. Inclure un "COUNT" juste pour contourner ce problème est très puant.
Michael Peterson
1
Puant? Si vous voulez l'appeler ainsi, bien sûr. Performant? Oui. C'est au développeur de décider des avantages et des inconvénients. C'est en fait la même réponse à la réponse de Zorayr ci-dessus où il entre plus en détail à ce sujet, et la nouvelle réponse acceptée est également similaire. Mais jusqu'à ce que Swift ajoute une API pour cela; c'est ce que certains d'entre nous ont décidé d'utiliser. Vous pouvez ajouter une fonction qui valide la valeur d'énumération guardcontre laquelle s COUNTet renvoie une erreur, renvoie false, etc. pour résoudre votre problème de représentation des types.
Drmorgan