enum Suit: String {
case spades = "♠"
case hearts = "♥"
case diamonds = "♦"
case clubs = "♣"
}
Wie kann ich zum Beispiel Folgendes tun:
for suit in Suit {
// do something with suit
print(suit.rawValue)
}
Resultierendes Beispiel:
♠
♥
♦
♣
Antworten:
Swift 4.2+
Beginnen Sie mit Swift 4.2 (mit Xcode 10) und fügen Sie einfach die Protokollkonformität hinzu, um davon
CaseIterable
zu profitierenallCases
. Um diese Protokollkonformität hinzuzufügen, müssen Sie einfach irgendwo schreiben:Wenn die Aufzählung Ihre eigene ist, können Sie die Konformität direkt in der Erklärung angeben:
Dann druckt der folgende Code alle möglichen Werte:
Kompatibilität mit früheren Swift-Versionen (3.x und 4.x)
Wenn Sie Swift 3.x oder 4.0 unterstützen müssen, können Sie die Swift 4.2-Implementierung nachahmen, indem Sie den folgenden Code hinzufügen:
quelle
String
im Gegensatz zur vorliegenden Frage zum Stapelüberlauf nicht unterstützt wird .Dieser Beitrag ist hier relevant https://www.swift-studies.com/blog/2014/6/10/enumerating-enums-in-swift
Im Wesentlichen ist die vorgeschlagene Lösung
quelle
Enum.Values(typeof(FooEnum))
jedoch als Erweiterungsmethode verfügbar gemacht wird (z. B. Map oder Reduce).FooEnum.values() :: values(EnumType -> [EnumType])
Ich habe eine Utility-Funktion
iterateEnum()
zum Iterieren von Fällen für beliebigeenum
Typen erstellt.Hier ist die Beispielverwendung:
Welche Ausgänge:
Dies dient jedoch nur zu Debug- oder Testzwecken: Dies hängt von mehreren undokumentierten Verhaltensweisen des Swift1.1-Compilers ab. Verwenden Sie ihn daher auf eigenes Risiko.
Hier ist der Code:
Die zugrunde liegende Idee ist:
enum
, mit Ausnahme vonenum
s mit zugehörigen Typen, ist nur ein Index von Fällen, wenn die Anzahl der Fälle2...256
identisch ist mitUInt8
, wann257...65536
,UInt16
und so weiter. Es kann sich also umunsafeBitcast
entsprechende vorzeichenlose Ganzzahltypen handeln..hashValue
Die Anzahl der Enum-Werte entspricht dem Index des Falls..hashValue
von Enum-Werten, die vom ungültigen Index bitcasted sind, ist0
.Überarbeitet für Swift2 und implementierte Casting-Ideen aus der Antwort von @ Kametrixom :
Überarbeitet für Swift3:
Überarbeitet für Swift3.0.1:
quelle
withUnsafePointer
withMemoryRebound
undpointee
andere Dinge lernen wollen , dann verwenden Sie diese auf jeden Fall. Sonst würde ich es vermeiden.Die anderen Lösungen funktionieren, aber alle gehen beispielsweise von der Anzahl der möglichen Ränge und Anzüge oder dem ersten und letzten Rang aus. Das Layout eines Kartenspiels wird sich in absehbarer Zeit wahrscheinlich nicht wesentlich ändern. Im Allgemeinen ist es jedoch ordentlicher, Code zu schreiben, der so wenig Annahmen wie möglich macht. Meine Lösung:
Ich habe der
Suit
Aufzählung einen Rohtyp hinzugefügt , damit ichSuit(rawValue:)
auf dieSuit
Fälle zugreifen kann :Nachfolgend die Implementierung der Card-
createDeck()
Methode.init(rawValue:)
ist ein fehlgeschlagener Initialisierer und gibt einen optionalen zurück. Wenn Sie den Wert in beiden while-Anweisungen auspacken und überprüfen, müssen Sie nicht die AnzahlRank
oder dieSuit
Fälle annehmen :Hier erfahren Sie, wie Sie das aufrufen
createDeck
Methode auf:quelle
Suit
. Sie können dies in diesem Beispiel tun, aber die Übung sollte Sie dazu bringen, mit dem zu arbeiten, dasenums
Ihnen gegeben wurde, als ob sie von einer externen Quelle stammten.Ich stolperte in den Bits und Bytes herum und erstellte eine Erweiterung, von der ich später herausfand, dass sie der Antwort von @rintaro sehr ähnlich ist . Es wird so verwendet:
Bemerkenswert ist, dass es für jede Aufzählung ohne zugehörige Werte verwendet werden kann. Beachten Sie, dass dies für Aufzählungen ohne Fälle nicht funktioniert.
Wie bei der Antwort von @rintaro verwendet dieser Code die zugrunde liegende Darstellung einer Aufzählung. Diese Darstellung ist nicht dokumentiert und könnte sich in Zukunft ändern, was sie beschädigen würde. Ich empfehle die Verwendung in der Produktion nicht.
Code (Swift 2.2, Xcode 7.3.1, funktioniert nicht mit Xcode 10):
Code (Swift 3, Xcode 8.1, funktioniert nicht mit Xcode 10):
Ich habe keine Ahnung, warum ich brauche
typealias
, aber der Compiler beschwert sich ohne es.quelle
withUnsafePointer
...pointee}
durchwithUnsafePointer(to: &i) { $0.withMemoryRebound(to: T.self, capacity: 1) { $0.pointee } }
Sie können eine Aufzählung durchlaufen, indem Sie das
ForwardIndexType
Protokoll implementieren .Für das
ForwardIndexType
Protokoll müssen Sie einesuccessor()
Funktion definieren, um die Elemente zu durchlaufen.Wenn Sie über einen offenen oder geschlossenen Bereich (
..<
oder...
) iterieren, wird intern diesuccessor()
Funktion aufgerufen, mit der Sie Folgendes schreiben können:quelle
successor()
Methode (erste Option) würde die Notwendigkeitenum
eines zugeordneten Typs beseitigen . +1Dieses Problem ist jetzt viel einfacher. Hier ist meine Swift 4.2-Lösung:
Pre 4.2:
Ich mag diese Lösung, die ich zusammengestellt habe, nachdem ich " Listenverständnis in Swift " gefunden habe.
Es verwendet Int-Rohdaten anstelle von Zeichenfolgen, vermeidet jedoch das zweimalige Eingeben, ermöglicht das Anpassen der Bereiche und codiert Rohwerte nicht fest.
Dies ist eine Swift 4-Version meiner ursprünglichen Lösung, aber siehe die 4.2-Verbesserung oben:
quelle
Im Prinzip ist dies auf diese Weise möglich, vorausgesetzt, Sie verwenden keine Rohwertzuweisung für die Fälle von enum:
quelle
enum ItWontWorkForThisEnum {case a, b, c}
Wenn Sie der Aufzählung einen rohen Int-Wert geben , wird das Schleifen viel einfacher.
Sie können beispielsweise
anyGenerator
einen Generator verwenden, der Ihre Werte auflistet:Dies sieht jedoch nach einem ziemlich häufigen Muster aus. Wäre es nicht schön, wenn wir einen Aufzählungstyp durch einfache Anpassung an ein Protokoll aufzählbar machen könnten? Nun, mit Swift 2.0 und Protokollerweiterungen können wir jetzt!
Fügen Sie dies einfach Ihrem Projekt hinzu:
Jedes Mal, wenn Sie eine Aufzählung erstellen (solange sie einen Int-Rohwert hat), können Sie sie durch Konformität mit dem Protokoll aufzählbar machen:
Wenn Ihre Aufzählungswerte nicht mit
0
(Standardeinstellung) beginnen, überschreiben Sie diefirstRawValue
Methode:Die letzte Suit-Klasse, einschließlich des Ersetzens
simpleDescription
durch das Standardprotokoll CustomStringConvertible , sieht folgendermaßen aus:Swift 3-Syntax:
quelle
Auf Swift 2.2 + aktualisiert
Der Code wurde auf das Swift 2.2-Formular aktualisiert @ Kametrixoms Antwort
Für Swift 3.0+ (vielen Dank an @Philip )
quelle
Swift 5 Lösung:
quelle
Ich habe
.allValues
in meinem gesamten Code viel getan . Ich habe endlich einen Weg gefunden, einfach einemIteratable
Protokoll zu entsprechen und einerawValues()
Methode zu haben.quelle
Xcode 10 mit Swift 4.2
Nennen
Drucke:
ältere Versionen
Zur
enum
DarstellungInt
Nennen Sie es so:
Drucke:
Zur
enum
DarstellungString
Nennen
Drucke:
quelle
BEARBEITEN: Swift Evolution-Vorschlag SE-0194 Die abgeleitete Sammlung von Enum-Fällen schlägt eine Lösung für dieses Problem vor. Wir sehen es in Swift 4.2 und neuer. Der Vorschlag weist auch auf einige Problemumgehungen hin , die den hier bereits erwähnten ähnlich sind, aber es könnte dennoch interessant sein, sie zu sehen.
Der Vollständigkeit halber werde ich auch meinen ursprünglichen Beitrag behalten.
Dies ist ein weiterer Ansatz, der auf der Antwort von @ Peymmankh basiert und an Swift 3 angepasst ist .
quelle
Wie wäre es damit?
quelle
Sie können versuchen, so aufzuzählen
quelle
static var enumerate = [Mercury, Venus, Earth, Mars]
einer unterdurchschnittlichen Antwort im Vergleich zu den am häufigsten gewähltenreturn [Mercury, Venus, Mars]
anstelle vonreturn [Mercury, Venus, Earth, Mars]
return [.spades, .hearts, .clubs]
sagt der Compiler nichts und wenn Sie versuchen, sie im Code zu verwenden, erhalten Sie[TestApp.Suit.spades, TestApp.Suit.hearts, TestApp.Suit.clubs]
- das war mein Punkt - das, wenn Sie es mit einem großen zu tun haben enum und Sie müssen von Zeit zu Zeit Fälle hinzufügen oder entfernen. Ihre Lösung ist anfällig für Auslassungsfehler, während die aktuelle Antwort zwar nicht präzise, aber sicherer ist.In Swift 3 können
rawValue
Sie dasStrideable
Protokoll implementieren , wenn die zugrunde liegende Aufzählung vorhanden ist . Die Vorteile sind, dass keine Arrays von Werten wie in einigen anderen Vorschlägen erstellt werden und dass die Standard-Swift-Schleife "for in" funktioniert, was eine schöne Syntax ergibt.quelle
Diese Lösung bietet das richtige Gleichgewicht zwischen Lesbarkeit und Wartbarkeit.
quelle
Entschuldigung, meine Antwort war spezifisch dafür, wie ich diesen Beitrag in dem verwendet habe, was ich tun musste. Für diejenigen, die über diese Frage stolpern und nach einem Weg suchen, einen Fall innerhalb einer Aufzählung zu finden, ist dies der Weg, dies zu tun (neu in Swift 2):
Bearbeiten: Kleinbuchstaben camelCase ist jetzt der Standard für Swift 3-Aufzählungswerte
Für diejenigen, die sich über die Aufzählung in einer Aufzählung wundern, sind die Antworten auf dieser Seite, die eine statische Variable / let enthalten, die ein Array aller Aufzählungswerte enthält, korrekt. Der neueste Apple-Beispielcode für tvOS enthält genau dieselbe Technik.
Davon abgesehen sollten sie einen bequemeren Mechanismus in die Sprache einbauen (Apple, hören Sie zu?)!
quelle
Das Experiment war: EXPERIMENT
Fügen Sie der Karte eine Methode hinzu, mit der ein vollständiges Kartenspiel mit einer Karte aus jeder Kombination aus Rang und Farbe erstellt wird.
Ohne den angegebenen Code zu ändern oder zu verbessern, außer die Methode hinzuzufügen (und ohne Dinge zu verwenden, die noch nicht gelehrt wurden), habe ich diese Lösung gefunden:
quelle
Hier ist eine Methode, mit der ich einen
enum
Wertetyp von einem iteriere und mehrere bereitstelleenum
Dies ist die Ausgabe:
Die Nummer Null auf Französisch: Zéro, Spanisch: Cero, Japanisch: Nuru
Die Nummer Eins auf Französisch: Un, Spanisch: Uno, Japanisch: Ichi
Die Nummer Zwei auf Französisch: Deux, Spanisch: Dos, Japanisch: Ni
Die Nummer Drei auf Französisch : trois, spanisch: tres, japanisch: san
Die Nummer Vier auf Französisch: Quatre, Spanisch: Cuatro, Japanisch: Shi
Die Nummer Fünf auf Französisch: Cinq, Spanisch: Cinco, Japanisch: Go
Die Nummer Sechs auf Französisch: Sechs, Spanisch: seis, japanisch: roku
Die Nummer Sieben auf Französisch: sept, spanisch: siete, japanisch: shichi
Insgesamt 8 Fälle
siete auf japanisch: shichi
AKTUALISIEREN
Ich habe kürzlich ein Protokoll für die Aufzählung erstellt. Das Protokoll erfordert eine Aufzählung mit einem Int-Rohwert:
quelle
Dies scheint ein Hack zu sein, aber wenn Sie Rohwerte verwenden, können Sie so etwas tun
quelle
Während
Swift 2.0
ich mich hier beschäftige, ist mein Vorschlag:Ich habe den Rohtyp hinzugefügt
Suit
enum
dann:
quelle
Wie bei @Kametrixom hier antworten glaube ich, dass die Rückgabe eines Arrays besser wäre als die Rückgabe von AnySequence, da Sie auf alle Extras des Arrays wie count usw. zugreifen können.
Hier ist das Umschreiben:
quelle
Eine andere Lösung:
quelle
Dies ist ein ziemlich alter Beitrag von Swift 2.0. Hier gibt es jetzt einige bessere Lösungen, die neuere Funktionen von Swift 3.0 verwenden: Durchlaufen einer Aufzählung in Swift 3.0
Und zu dieser Frage gibt es eine Lösung, die eine neue Funktion von Swift 4.2 verwendet (die noch nicht veröffentlicht wurde, während ich diese Bearbeitung schreibe): Wie erhalte ich die Anzahl einer Swift-Enumeration?
Es gibt viele gute Lösungen in diesem Thread und andere, einige davon sind jedoch sehr kompliziert. Ich möchte so viel wie möglich vereinfachen. Hier ist eine Lösung, die möglicherweise für unterschiedliche Anforderungen funktioniert oder nicht, aber ich denke, dass sie in den meisten Fällen gut funktioniert:
So wiederholen Sie:
quelle
Aufzählungen haben
toRaw()
undfromRaw()
Methoden. Wenn Ihr Rohwert also ein istInt
, können Sie vom ersten bis zum letzten iterierenenum
:Ein Problem ist, dass Sie vor dem Ausführen der
simpleDescription
Methode auf optionale Werte testen müssen. Daher setzenconvertedSuit
wir zuerst unseren Wert und dann eine Konstante aufconvertedSuit.simpleDescription()
quelle
Hier ist mein vorgeschlagener Ansatz. Es ist nicht ganz zufriedenstellend (ich bin sehr neu bei Swift und OOP!), Aber vielleicht kann es jemand verfeinern. Die Idee ist, dass jede Aufzählung ihre eigenen Bereichsinformationen
.first
und.last
Eigenschaften bereitstellt . Es werden nur zwei Codezeilen zu jeder Aufzählung hinzugefügt: immer noch ein bisschen hartcodiert, aber zumindest wird nicht der gesamte Satz dupliziert. Es ist erforderlich, dieSuit
Aufzählung so zu ändern, dass sie ein Int wie das istRank
Aufzählung ist, anstatt untypisiert zu sein.Anstatt die gesamte Lösung
.
wiederzugeben, ist hier der Code, den ich irgendwo nach den case-Anweisungen zur Aufzählung hinzugefügt habe (Suit
Aufzählung ist ähnlich):und die Schleife, mit der ich das Deck als Array von String erstellt habe. (Die Problemdefinition gab nicht an, wie das Deck strukturiert werden sollte.)
Dies ist unbefriedigend, da die Eigenschaften eher einem Element als der Aufzählung zugeordnet sind. Aber es fügt den 'for'-Schleifen Klarheit hinzu. Ich möchte, dass es
Rank.first
statt sagtRank.Ace.first
. Es funktioniert (mit jedem Element), aber es ist hässlich. Kann jemand zeigen, wie man das auf die Enum-Ebene hebt?Und damit es funktioniert, habe ich die
createDeck
Methode aus der Kartenstruktur entfernt. Ich konnte nicht herausfinden, wie ein [String] -Array von dieser Struktur zurückgegeben werden kann, und das scheint ohnehin ein schlechter Ort zu sein, um eine solche Methode einzusetzen.quelle
Ich habe es mit einer berechneten Eigenschaft gemacht, die das Array aller Werte zurückgibt (dank dieses Beitrags http://natecook.com/blog/2014/10/loopy-random-enum-ideas/ ). Es werden jedoch auch int-Rohwerte verwendet, aber ich muss nicht alle Mitglieder der Aufzählung in einer separaten Eigenschaft wiederholen.
UPDATE Xcode 6.1 hat die Art und Weise, wie Enum-Mitglieder verwendet werden
rawValue
, ein wenig geändert , daher habe ich die Auflistung korrigiert. Auch kleiner Fehler mit falschem zuerst behobenrawValue
.quelle
Basierend auf Rick Antwort: Dies ist 5 mal schneller
quelle
Count
Falls werden umfassendeswitch
Implementierungen undCaseIterable
Konformitäten beeinträchtigt.