Wie erhalte ich die Zählung einer Swift-Aufzählung?

Antworten:

171

Ab Swift 4.2 (Xcode 10) können Sie die Konformität mit dem CaseIterableProtokoll deklarieren. Dies funktioniert für alle Aufzählungen ohne zugehörige Werte:

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

Die Anzahl der Fälle wird nun einfach mit ermittelt

print(Stuff.allCases.count) // 4

Weitere Informationen finden Sie unter

Martin R.
quelle
1
In der neuesten Version von swift entspricht der Fehler "Typ 'DAFFlow' nicht dem Protokoll 'RawRepresentable'". Warum zwingt es mich, dem zu folgen? Irgendeine Idee?
Satyam
@ Satyam: Was ist DAFFlow?
Martin R
Entschuldigung, ich habe vergessen zu erwähnen, dass "DAFFlow" eine einfache Aufzählung ist, die von keinem anderen Protokoll erbt.
Satyam
1
Dies ist die beste Lösung, aber nur aus Gründen der Übersichtlichkeit - Apple-Entwickler können diese erst dann wirklich verwenden, wenn Xcode 10 (und damit Swift 4.2) die Beta-Version verlassen hat (voraussichtlich um den 14. September 2018).
JosephH
1
@DaniSpringer: Die wichtigsten Details finden Sie unter github.com/apple/swift-evolution/blob/master/proposals/… . Normalerweise benötigen Sie diesen Typ aufgrund der automatischen Typinferenz des Compilers nicht explizit.
Martin R
143

Ich habe einen Blog-Beitrag , der ausführlicher darauf eingeht, aber solange der Rohtyp Ihrer Aufzählung eine Ganzzahl ist, können Sie auf diese Weise eine Zählung hinzufügen:

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
quelle
16
Dies ist zwar hilfreich, da Sie keinen Wert fest codieren müssen, es instanziiert jedoch bei jedem Aufruf jeden Aufzählungswert. Das ist O (n) anstelle von O (1). :(
Code Commander
4
Dies ist eine gute Lösung für zusammenhängende Int. Ich bevorzuge eine leichte Modifikation. Verwandeln Sie die Eigenschaft static count in eine statische Methode countCases () und weisen Sie sie einer statischen Konstante caseCount zu, die faul ist und die Leistung bei wiederholten Aufrufen verbessert.
Tom Pelaia
2
@ShamsAhmed: Konvertierte die berechnete Variable in eine statische.
Nate Cook
3
Was ist, wenn Sie einen Wert in der Aufzählung verpassen? zB case A=1, B=3?
Sasho
2
Es gibt zwei Annahmen neben der enumeinen mit IntRohwert , dass Sie vergessen zu erwähnen: Swift Enum ist mit Int Rohwerte nicht über 0 starten (auch wenn das das Standardverhalten) und ihre Ausgangswerte willkürlich können, haben sie nicht um 1 erhöhen (obwohl dies das Standardverhalten ist).
Dávid Pásztor
90

Xcode 10 Update

Übernehmen Sie das CaseIterableProtokoll in die Aufzählung, es bietet eine statische allCasesEigenschaft, die alle Aufzählungsfälle als enthält Collection. Verwenden Sie einfach seine countEigenschaft, um zu wissen, wie viele Fälle die Aufzählung hat.

Ein Beispiel finden Sie in Martins Antwort (und stimmen Sie eher seinen als meinen Antworten zu)


Warnung : Die folgende Methode scheint nicht mehr zu funktionieren.

Mir ist keine generische Methode bekannt, um die Anzahl der Enum-Fälle zu zählen. Ich habe jedoch festgestellt, dass die hashValueEigenschaft der Enum-Fälle inkrementell ist, beginnend bei Null und mit der Reihenfolge, die durch die Reihenfolge bestimmt wird, in der die Fälle deklariert werden. Der Hash der letzten Aufzählung plus eins entspricht also der Anzahl der Fälle.

Zum Beispiel mit dieser Aufzählung:

enum Test {
    case ONE
    case TWO
    case THREE
    case FOUR

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

count gibt 4 zurück.

Ich kann nicht sagen, ob dies eine Regel ist oder ob sie sich in Zukunft jemals ändern wird. Verwenden Sie sie daher auf eigenes Risiko :)

Antonio
quelle
48
Lebe nach der undokumentierten Funktion, sterbe nach der undokumentierten Funktion. Ich mag das!
Nate Cook
9
Wir sollten uns hashValuesbei diesen Dingen nicht wirklich darauf verlassen . Wir wissen nur, dass es sich um einen zufälligen eindeutigen Wert handelt, der sich in Zukunft sehr leicht ändern kann, abhängig von einigen Details der Compiler-Implementierung. Insgesamt ist der Mangel an eingebauter Zählfunktion jedoch störend.
Zorayr
16
Wenn Sie nicht explizit Einstellung nichts ausmacht case ONE = 0, können Sie ersetzen Sie dann hashValuemit rawValue.
Kevin Qi
3
Hier geht es um die Verwendung einer undokumentierten Eigenschaft von hashValue. Daher empfehle ich, eine dokumentierte Eigenschaft von rawValue zu verwenden.
Kevin Qi
7
Sie haben bereits fest codiert, welche Konstante der höchste Wert ist. Besser und sicherer, nur so etwas zu verwenden, static var count = 4als Ihr Schicksal im Schicksal zukünftiger Implementierungen von Swift
Dale
72

Ich definiere ein wiederverwendbares Protokoll, das automatisch die Fallzählung basierend auf dem von Nate Cook veröffentlichten Ansatz durchführt.

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

Dann kann ich dieses Protokoll beispielsweise wie folgt wiederverwenden:

enum Planet : Int, CaseCountable {
    case Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
}
//..
print(Planet.caseCount)
Tom Pelaia
quelle
1
Schön und elegant, sollte die akzeptierte Antwort IMHO
Shannoga
1
Vielleicht ist es besser zu wechseln count++, count+=1da die ++Notation in Swift 3
Aladin
1
konnte das nicht auch nur gemacht werden static var caseCount: Int { get }? warum die Notwendigkeit für die static func?
pxpgraphics
Was ist, wenn Sie einen Wert in der Aufzählung verpassen? zB case A=1, B=3?
Sasho
1
@Sasho, dann wird es nicht funktionieren. Dies setzt voraus, dass Ihre Fälle beginnen 0und keine Lücken aufweisen.
NRitH
35

Erstellen Sie ein statisches allValues-Array wie in dieser Antwort gezeigt

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

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

...

let count = ProductCategory.allValues.count

Dies ist auch hilfreich, wenn Sie die Werte auflisten möchten, und funktioniert für alle Aufzählungstypen

david72
quelle
Obwohl nicht so elegant wie die Erweiterungslösung und sehr manuell, glaube ich, dass dies am nützlichsten ist, da es viel mehr als nur Zählung bietet. Sie erhalten eine Reihenfolge der Werte und eine Liste aller Werte.
Nader Eloshaiker
2
Sie können die Anzahl auch zur Aufzählung hinzufügen, indem Sie dies tun static let count = allValues.count. Dann können Sie das allValuesprivat machen, wenn Sie gewünscht werden.
ThomasW
15

Wenn die Implementierung nichts gegen die Verwendung ganzzahliger Aufzählungen hat, können Sie einen zusätzlichen Elementwert hinzufügen, der aufgerufen wird Count, um die Anzahl der Elemente in der Aufzählung darzustellen - siehe Beispiel unten:

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

Jetzt können Sie die Anzahl der Mitglieder in der Enumeration durch Aufrufen abrufen TableViewSections.Count.rawValue. Im obigen Beispiel wird 2 zurückgegeben.

Wenn Sie die Aufzählung in einer switch-Anweisung behandeln, stellen Sie sicher, dass ein Assertionsfehler ausgelöst wird, wenn Sie auf das CountMitglied stoßen, bei dem Sie es nicht erwarten:

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
quelle
Ich mag diese Lösung, da sie die Anzahl automatisch ändert, wenn weitere Aufzählungswerte hinzugefügt werden. Beachten Sie jedoch, dass dies nur funktioniert, wenn die rawValues ​​der Aufzählung mit 0 beginnen.
joern
2
Stimmen Sie zu, es gibt zwei Einschränkungen: Sie müssen eine ganzzahlige Aufzählung sein und bei Null beginnen und schrittweise fortgesetzt werden.
Zorayr
3
Ich dachte, der ganze Sinn von Swifts mächtigeren Aufzählungen war, dass wir nicht die gleichen Hacks verwenden müssten, die wir in Objective-C verwendet haben: /
pkamb
14

Diese Art von Funktion kann die Anzahl Ihrer Aufzählung zurückgeben.

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
quelle
3
Dies funktioniert nicht mehr für Swift 3. Der Versuch, die richtige Implementierung zu erarbeiten, ist jedoch leer
Cody Winton
Dies wird sehr Unfun zu debuggen, wenn die Speicheradresse unmittelbar neben dem Ende der enumist auch Hashable vom gleichen Typ.
NRitH
10

String Enum mit 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)!
    }
}

Anzahl : eEventTabType.allValues.count

Index : objeEventTabType.index

Genießen :)

Kalpesh Jetani
quelle
10

Oh hey alle zusammen, was ist mit Unit-Tests?

func testEnumCountIsEqualToNumberOfItemsInEnum() {

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

    XCTAssert(max == Test.count)
}

Dies kombiniert mit Antonios Lösung:

enum Test {

    case one
    case two
    case three
    case four

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

Im Hauptcode erhalten Sie O (1) und Sie erhalten einen fehlgeschlagenen Test, wenn jemand einen Enum-Fall hinzufügt fiveund die Implementierung von nicht aktualisiert count.

Builds erfolgreich
quelle
7

Diese Funktion basiert auf 2 undokumentierten aktuellen (Swift 1.1) enumVerhalten:

  • Das Speicherlayout von enumist nur ein Index von case. Wenn die Anzahl der Fälle zwischen 2 und 256 liegt, ist dies der Fall UInt8.
  • Wenn das enumaus einem ungültigen Fallindex bitweise umgewandelt wurde , hashValueist es0

Also auf eigenes Risiko verwenden :)

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

Verwendung:

enum Foo:String {
    case C000 = "foo"
    case C001 = "bar"
    case C002 = "baz"
}
enumCaseCount(Foo) // -> 3
Rintaro
quelle
In Release und Ad-hoc-Anwendung wird CRASH
HotJard
Dies funktioniert im Simulator, jedoch nicht auf einem echten 64-Bit-Gerät.
Daniel Nord
5

Ich habe eine einfache Erweiterung geschrieben, die allen Aufzählungen, bei denen der Rohwert eine Ganzzahl ist, eine countEigenschaft gibt:

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

Leider gibt es die countEigenschaft, OptionSetTypewo es nicht richtig funktioniert, daher ist hier eine andere Version, die eine explizite Konformität mit dem CaseCountableProtokoll für jede Aufzählung erfordert, welche Fälle Sie zählen möchten:

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

Es ist dem von Tom Pelaia veröffentlichten Ansatz sehr ähnlich, funktioniert jedoch mit allen ganzzahligen Typen.

bzz
quelle
4

Natürlich ist es nicht dynamisch, aber für viele Zwecke können Sie mit einer statischen Variable auskommen, die Ihrer Aufzählung hinzugefügt wurde

static var count: Int{ return 7 }

und dann verwenden als EnumName.count

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

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

print(EnumNameType.count) //3

ODER

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

print(EnumNameType.count.rawValue) //3

* Auf Swift 4.2 (Xcode 10) kann verwendet werden:

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

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

Für meinen Anwendungsfall ist es in einer Codebasis, in der mehrere Personen einer Aufzählung Schlüssel hinzufügen können und diese Fälle alle in der Eigenschaft allKeys verfügbar sein sollten, wichtig, dass allKeys anhand der Schlüssel in der Aufzählung überprüft wird. Dies soll verhindern, dass jemand vergisst, seinen Schlüssel zur Liste aller Schlüssel hinzuzufügen.Durch Abgleichen der Anzahl des allKeys-Arrays (das zuerst als Satz erstellt wurde, um Dupes zu vermeiden) mit der Anzahl der Schlüssel in der Aufzählung wird sichergestellt, dass alle vorhanden sind.

Einige der obigen Antworten zeigen, wie dies in Swift 2 erreicht werden kann, aber in Swift 3 funktioniert keine . Hier ist die Swift 3- formatierte Version:

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

Abhängig von Ihrem Anwendungsfall möchten Sie den Test möglicherweise nur in der Entwicklung ausführen, um den Aufwand für die Verwendung von allKeys bei jeder Anforderung zu vermeiden

Chris Mitchelmore
quelle
2

Warum machst du das alles so komplex? Der EINFACHSTE Zähler von Int enum ist das Hinzufügen von:

case Count

Schlussendlich. Und ... Bratsche - jetzt haben Sie die Zählung - schnell und einfach

Dimitar Marinov
quelle
1
Dies a) fügt einen irrelevanten Aufzählungsfall hinzu und b) funktioniert nicht, wenn der Rohtyp der Aufzählung etwas anderes als Int ist.
Robert Atkins
Das ist eigentlich keine schlechte Antwort. Wie bei der obigen Antwort von @Tom Pelaia müssen die Rohwerte jedoch bei beginnen 0und dürfen keine Lücken in der Sequenz aufweisen.
NRitH
1

Wenn Sie Ihren Code nicht auf der letzten Aufzählung basieren möchten, können Sie diese Funktion in Ihrer Aufzählung erstellen.

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

Eine Swift 3- Version, die mit IntTypaufzählungen arbeitet:

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

Credits: Basierend auf den Antworten von bzz und Nate Cook.

Generic IntegerType(in Swift 3 umbenannt in Integer) wird nicht unterstützt, da es sich um einen stark fragmentierten generischen Typ handelt, dem viele Funktionen fehlen. successorist mit Swift 3 nicht mehr verfügbar.

Beachten Sie, dass der Kommentar von Code Commander zur Antwort von Nate Cooks weiterhin gültig ist:

Dies ist zwar hilfreich, da Sie keinen Wert fest codieren müssen, es instanziiert jedoch bei jedem Aufruf jeden Aufzählungswert. Das ist O (n) anstelle von O (1).

Soweit ich weiß, gibt es derzeit keine Problemumgehung, wenn Sie diese als Protokollerweiterung verwenden (und nicht wie Nate Cook in jeder Aufzählung implementieren), da statische gespeicherte Eigenschaften in generischen Typen nicht unterstützt werden.

Auf jeden Fall sollte dies für kleine Aufzählungen kein Problem sein. Ein typischer Anwendungsfall wäre die section.countfür UITableViewswie bereits von Zorayr erwähnt.

Frederik Winkelsdorf
quelle
1

Erweiterung der Antwort von Matthieu Riegler: Dies ist eine Lösung für Swift 3 , für die keine Generika erforderlich sind. Sie kann einfach mit dem Aufzählungstyp aufgerufen werden mit 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
quelle
0

Ich habe dieses Problem für mich selbst gelöst, indem ich ein Protokoll (EnumIntArray) und eine globale Dienstprogrammfunktion (enumIntArray) erstellt habe, mit denen es sehr einfach ist, einer Aufzählung eine "All" -Variable hinzuzufügen (mit swift 1.2). Die Variable "all" enthält ein Array aller Elemente in der Aufzählung, sodass Sie all.count für die Zählung verwenden können

Es funktioniert nur mit Aufzählungen, die Rohwerte vom Typ Int verwenden, kann aber möglicherweise Inspiration für andere Typen liefern.

Es befasst sich auch mit den Problemen "Nummerierung" und "übermäßiger Zeit zum Iterieren", die ich oben und anderswo gelesen habe.

Die Idee ist, das EnumIntArray-Protokoll zu Ihrer Aufzählung hinzuzufügen und dann eine statische Variable "all" zu definieren, indem Sie die Funktion enumIntArray aufrufen und das erste Element (und das letzte, wenn es Lücken in der Nummerierung gibt) bereitstellen.

Da die statische Variable nur einmal initialisiert wird, trifft der Aufwand für das Durchlaufen aller Rohwerte Ihr Programm nur einmal.

Beispiel (ohne Lücken):

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

Beispiel (mit Lücken):

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

Hier ist der Code, der es implementiert:

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.
quelle
0

Oder Sie können einfach die _countAußenseite der Aufzählung definieren und statisch anhängen:

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
}

Auf diese Weise wird die Anzahl der von Ihnen erstellten Aufzählungen immer nur einmal erstellt.

(Löschen Sie diese Antwort, wenn dies der staticFall ist.)

BEIM
quelle
0

Die folgende Methode stammt von CoreKit und ähnelt den Antworten, die einige andere vorgeschlagen haben. Dies funktioniert mit 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
}

Dann müssen Sie nur noch anrufen Weekdays.allValues.count.

ThomasW
quelle
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
quelle
-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

Seien Sie jedoch vorsichtig bei der Verwendung mit Nicht-Enum-Typen. Einige Problemumgehungen könnten sein:

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

Es kann eine statische Konstante verwendet werden, die den letzten Wert der Aufzählung plus eins enthält.

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
quelle
-3

Dies ist geringfügig, aber ich denke, eine bessere O (1) -Lösung wäre die folgende ( NUR, wenn Ihre Aufzählung Intbei x usw. beginnt):

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 
}

Die aktuell ausgewählte Antwort ist meines Erachtens immer noch die beste Antwort für alle Aufzählungen. Wenn Sie nicht mit Intdieser Antwort arbeiten, empfehle ich diese Lösung.

Drmorgan
quelle
3
Das Hinzufügen eines Werts zu Ihrer Aufzählung, der nicht den Typ der Aufzählung darstellt, ist ein schlechter Codegeruch. Es fällt mir schwer, die Aufnahme eines "ALL" oder "NONE" zu rechtfertigen, obwohl es manchmal verlockend sein kann. Das Einfügen eines "COUNT", nur um dieses Problem zu umgehen, ist sehr stinkend.
Michael Peterson
1
Stinkend? Wenn du es so sicher nennen willst. Performant? Ja. Es ist Sache des Entwicklers, die Vor- und Nachteile zu bestimmen. Dies ist tatsächlich die gleiche Antwort auf Zorayrs Antwort oben, in der er ausführlicher darauf eingeht, und die neu akzeptierte Antwort ist ebenfalls ähnlich. Aber bis schnell eine API dafür hinzufügt; Dies ist, was einige von uns beschlossen haben, zu verwenden. Sie können eine Funktion hinzufügen, die den Aufzählungswert überprüft, guardgegen den COUNTein Fehler ausgegeben wird, der false zurückgibt usw., um Ihr Problem der Darstellung von Typen zu lösen.
Drmorgan