enum Suit: String {
case spades = "♠"
case hearts = "♥"
case diamonds = "♦"
case clubs = "♣"
}
Par exemple, comment puis-je faire quelque chose comme:
for suit in Suit {
// do something with suit
print(suit.rawValue)
}
Exemple résultant:
♠
♥
♦
♣
À partir de Swift 4.2 (avec Xcode 10), ajoutez simplement la conformité du protocole à CaseIterable
pour bénéficier de allCases
:
extension Suit: CaseIterable {}
Ensuite, toutes les valeurs possibles seront imprimées:
Suit.allCases.forEach {
print($0.rawValue)
}
Juste imiter l'implémentation de Swift 4.2:
#if !Swift(>=4.2)
public protocol CaseIterable {
associatedtype AllCases: Collection where AllCases.Element == Self
static var allCases: AllCases { get }
}
extension CaseIterable where Self: Hashable {
static var allCases: [Self] {
return [Self](AnySequence { () -> AnyIterator<Self> in
var raw = 0
var first: Self?
return AnyIterator {
let current = withUnsafeBytes(of: &raw) { $0.load(as: Self.self) }
if raw == 0 {
first = current
} else if current == first {
return nil
}
raw += 1
return current
}
})
}
}
#endif
Cet article est pertinent ici https://www.Swift-studies.com/blog/2014/6/10/enumerating-enums-in-Swift
La solution proposée est essentiellement
enum ProductCategory : String {
case Washers = "washers", Dryers = "dryers", Toasters = "toasters"
static let allValues = [Washers, Dryers, Toasters]
}
for category in ProductCategory.allValues{
//Do something
}
J'ai créé une fonction utilitaire iterateEnum()
pour itérer des observations pour des types enum
arbitraires.
Voici l'exemple d'utilisation:
enum Suit:String {
case Spades = "♠"
case Hearts = "♥"
case Diamonds = "♦"
case Clubs = "♣"
}
for f in iterateEnum(Suit) {
println(f.rawValue)
}
les sorties:
♠
♥
♦
♣
Mais cela ne concerne que uniquement à des fins de débogage ou de test: Cela repose sur plusieurs comportements de compilateur actuels non documentés (Swift1.1). Alors, utilisez-le à vos risques et périls :)
Voici le code:
func iterateEnum<T: Hashable>(_: T.Type) -> GeneratorOf<T> {
var cast: (Int -> T)!
switch sizeof(T) {
case 0: return GeneratorOf(GeneratorOfOne(unsafeBitCast((), T.self)))
case 1: cast = { unsafeBitCast(UInt8(truncatingBitPattern: $0), T.self) }
case 2: cast = { unsafeBitCast(UInt16(truncatingBitPattern: $0), T.self) }
case 4: cast = { unsafeBitCast(UInt32(truncatingBitPattern: $0), T.self) }
case 8: cast = { unsafeBitCast(UInt64($0), T.self) }
default: fatalError("cannot be here")
}
var i = 0
return GeneratorOf {
let next = cast(i)
return next.hashValue == i++ ? next : nil
}
}
L'idée sous-jacente est:
enum
- à l'exclusion de enum
s avec les types associés - est simplement un index de cas, lorsque le nombre de cas est 2...256
, il est identique à UInt8
, quand 257...65536
, c'est UInt16
, etc. Donc, il peut s'agir de unsafeBitcast
parmi les types entiers non signés correspondants..hashValue
of enum values est identique à l'index du cas..hashValue
des valeurs énumérées bitcastées à partir de invalide index est 0
AJOUTÉE:
Révisé pour Swift2 et mis en œuvre des idées de casting de @ Kametrixom's answer
func iterateEnum<T: Hashable>(_: T.Type) -> AnyGenerator<T> {
var i = 0
return anyGenerator {
let next = withUnsafePointer(&i) { UnsafePointer<T>($0).memory }
return next.hashValue == i++ ? next : nil
}
}
ADDED: Révisé pour Swift3
func iterateEnum<T: Hashable>(_: T.Type) -> AnyIterator<T> {
var i = 0
return AnyIterator {
let next = withUnsafePointer(to: &i) {
$0.withMemoryRebound(to: T.self, capacity: 1) { $0.pointee }
}
if next.hashValue != i { return nil }
i += 1
return next
}
}
ADDED: Révisé pour Swift3.0.1
func iterateEnum<T: Hashable>(_: T.Type) -> AnyIterator<T> {
var i = 0
return AnyIterator {
let next = withUnsafeBytes(of: &i) { $0.load(as: T.self) }
if next.hashValue != i { return nil }
i += 1
return next
}
}
Les autres solutions fonctionnent mais elles supposent toutes, par exemple, le nombre de rangs et de combinaisons possibles, ou ce que peuvent être le premier et le dernier rang. Certes, la disposition d'un jeu de cartes ne changera probablement pas beaucoup dans un avenir proche. En général, cependant, il est préférable d'écrire du code qui suppose le moins possible d'hypothèses. Ma solution:
J'ai ajouté un type brut à l'énumération de costume, je peux donc utiliser Suit (rawValue :) pour accéder aux cas de Suit:
enum Suit: Int {
case Spades = 1
case Hearts, Diamonds, Clubs
func simpleDescription() -> String {
switch self {
case .Spades:
return "spades"
case .Hearts:
return "hearts"
case .Diamonds:
return "diamonds"
case .Clubs:
return "clubs"
}
}
func color() -> String {
switch self {
case .Spades:
return "black"
case .Clubs:
return "black"
case .Diamonds:
return "red"
case .Hearts:
return "red"
}
}
}
enum Rank: Int {
case Ace = 1
case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
case Jack, Queen, King
func simpleDescription() -> String {
switch self {
case .Ace:
return "ace"
case .Jack:
return "jack"
case .Queen:
return "queen"
case .King:
return "king"
default:
return String(self.rawValue)
}
}
}
Ci-dessous l'implémentation de la méthode createDeck () de Card. init (rawValue :) est un initialiseur disponible et retourne un optionnel. En décompressant et en vérifiant sa valeur dans les deux déclarations while, il n'est pas nécessaire de supposer le nombre de cas Rank ou Suit:
struct Card {
var rank: Rank
var suit: Suit
func simpleDescription() -> String {
return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
}
func createDeck() -> [Card] {
var n = 1
var deck = [Card]()
while let rank = Rank(rawValue: n) {
var m = 1
while let suit = Suit(rawValue: m) {
deck.append(Card(rank: rank, suit: suit))
m += 1
}
n += 1
}
return deck
}
}
Voici comment appeler la méthode createDeck:
let card = Card(rank: Rank.Ace, suit: Suit.Clubs)
let deck = card.createDeck()
Donc, je suis tombé sur les bits et les octets et j'ai créé une extension (que j'ai découvert par la suite, fonctionne très similaire à la réponse de @rintaro ). C'est utilisable comme ça:
enum E : EnumCollection {
case A, B, C
}
Array(E.cases()) // [A, B, C]
Ce qui est remarquable, c’est qu’il est utilisable sur n’importe quel enum (sans valeurs associées). Notez que cela ne fonctionne pas pour les enums qui n'ont pas de cas.
Comme avec la réponse de @rintaro , ce code utilise la représentation sous-jacente d'un enum. Cette représentation n'est pas documentée et pourrait changer dans le futur, ce qui la casserait -> Je ne recommande pas son utilisation en production.
protocol EnumCollection : Hashable {}
extension EnumCollection {
static func cases() -> AnySequence<Self> {
typealias S = Self
return AnySequence { () -> AnyGenerator<S> in
var raw = 0
return AnyGenerator {
let current : Self = withUnsafePointer(&raw) { UnsafePointer($0).memory }
guard current.hashValue == raw else { return nil }
raw += 1
return current
}
}
}
}
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
}
}
}
}
(Je ne sais pas pourquoi j'ai besoin de typealias
, mais le compilateur se plaint de ne pas en avoir)
(J'ai apporté de grandes modifications à cette réponse, regardez les modifications des versions antérieures)
Vous pouvez parcourir une énumération en implémentant le protocole ForwardIndexType
.
Le protocole ForwardIndexType
nécessite que vous définissiez une fonction successor()
pour parcourir les éléments.
enum Rank: Int, ForwardIndexType {
case Ace = 1
case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
case Jack, Queen, King
// ... other functions
// Option 1 - Figure it out by hand
func successor() -> Rank {
switch self {
case .Ace:
return .Two
case .Two:
return .Three
// ... etc.
default:
return .King
}
}
// Option 2 - Define an operator!
func successor() -> Rank {
return self + 1
}
}
// NOTE: The operator is defined OUTSIDE the class
func + (left: Rank, right: Int) -> Rank {
// I'm using to/from raw here, but again, you can use a case statement
// or whatever else you can think of
return left == .King ? .King : Rank(rawValue: left.rawValue + right)!
}
Une itération sur une plage ouverte ou fermée (..<
ou ...
) appelle en interne la fonction successor()
qui vous permet d'écrire ceci:
// Under the covers, successor(Rank.King) and successor(Rank.Ace) are called to establish limits
for r in Rank.Ace...Rank.King {
// Do something useful
}
En principe, il est possible de le faire de cette manière en supposant que vous n'utilisez pas l'affectation de valeurs brutes pour les cas d'enum:
enum RankEnum: Int {
case Ace
case One
case Two
}
class RankEnumGenerator : Generator {
var i = 0
typealias Element = RankEnum
func next() -> Element? {
let r = RankEnum.fromRaw(i)
i += 1
return r
}
}
extension RankEnum {
static func enumerate() -> SequenceOf<RankEnum> {
return SequenceOf<RankEnum>({ RankEnumGenerator() })
}
}
for r in RankEnum.enumerate() {
println("\(r.toRaw())")
}
Si vous donnez l'énum une valeur Int brute cela facilitera grandement la lecture en boucle.
Par exemple, vous pouvez utiliser anyGenerator
pour obtenir un générateur pouvant énumérer vos valeurs:
enum Suit: Int, CustomStringConvertible {
case Spades, Hearts, Diamonds, Clubs
var description: String {
switch self {
case .Spades: return "Spades"
case .Hearts: return "Hearts"
case .Diamonds: return "Diamonds"
case .Clubs: return "Clubs"
}
}
static func enumerate() -> AnyGenerator<Suit> {
var nextIndex = Spades.rawValue
return anyGenerator { Suit(rawValue: nextIndex++) }
}
}
// You can now use it like this:
for suit in Suit.enumerate() {
suit.description
}
// or like this:
let allSuits: [Suit] = Array(Suit.enumerate())
Cependant, cela ressemble à un modèle assez commun, ne serait-ce pas Nice si nous pouvions rendre tout type énumérable énumérable en se conformant simplement à un protocole? Eh bien avec Swift 2.0 et les extensions de protocole, maintenant nous le pouvons!
Ajoutez simplement ceci à votre projet:
protocol EnumerableEnum {
init?(rawValue: Int)
static func firstValue() -> Int
}
extension EnumerableEnum {
static func enumerate() -> AnyGenerator<Self> {
var nextIndex = firstRawValue()
return anyGenerator { Self(rawValue: nextIndex++) }
}
static func firstRawValue() -> Int { return 0 }
}
Maintenant, chaque fois que vous créez une énumération (tant qu'elle a une valeur brute Int), vous pouvez la rendre énumérable en vous conformant au protocole:
enum Rank: Int, EnumerableEnum {
case Ace, Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King
}
// ...
for rank in Rank.enumerate() { ... }
Si vos valeurs enum ne commencent pas par 0
(valeur par défaut), remplacez la méthode firstRawValue
:
enum DeckColor: Int, EnumerableEnum {
case Red = 10, Blue, Black
static func firstRawValue() -> Int { return Red.rawValue }
}
// ...
let colors = Array(DeckColor.enumerate())
La classe Suit finale, comprenant le remplacement de simpleDescription
par le protocole plus standard, CustomStringConvertible , ressemblera à ceci:
enum Suit: Int, CustomStringConvertible, EnumerableEnum {
case Spades, Hearts, Diamonds, Clubs
var description: String {
switch self {
case .Spades: return "Spades"
case .Hearts: return "Hearts"
case .Diamonds: return "Diamonds"
case .Clubs: return "Clubs"
}
}
}
// ...
for suit in Suit.enumerate() {
print(suit.description)
}
MODIFIER:
Swift 3
syntaxe:
protocol EnumerableEnum {
init?(rawValue: Int)
static func firstRawValue() -> Int
}
extension EnumerableEnum {
static func enumerate() -> AnyIterator<Self> {
var nextIndex = firstRawValue()
let iterator: AnyIterator<Self> = AnyIterator {
defer { nextIndex = nextIndex + 1 }
return Self(rawValue: nextIndex)
}
return iterator
}
static func firstRawValue() -> Int {
return 0
}
}
Mis à jour à Swift 2.2 +
func iterateEnum<T: Hashable>(_: 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
}
}
}
son code est mis à jour au format Swift 2.2 @ @ Kametrixom swer
Pour Swift 3.0+ (merci beaucoup à @Philip )
func iterateEnum<T: Hashable>(_: T.Type) -> AnyIterator<T> {
var i = 0
return AnyIterator {
let next = withUnsafePointer(&i) {
UnsafePointer<T>($0).pointee
}
if next.hashValue == i {
i += 1
return next
} else {
return nil
}
}
}
Ce problème est maintenant beaucoup plus facile. Voici ma solution Swift 4.2.
enum Suit: Int, CaseIterable {
case None
case Spade, Heart, Diamond, Club
static let allNonNullCases = Suit.allCases[Spade.rawValue...]
}
enum Rank: Int, CaseIterable {
case Joker
case Two, Three, Four, Five, Six, Seven, Eight
case Nine, Ten, Jack, Queen, King, Ace
static let allNonNullCases = Rank.allCases[Two.rawValue...]
}
func makeDeck(withJoker: Bool = false) -> [Card] {
var deck = [Card]()
for suit in Suit.allNonNullCases {
for rank in Rank.allNonNullCases {
deck.append(Card(suit: suit, rank: rank))
}
}
if withJoker {
deck.append(Card(suit: .None, rank: .Joker))
}
return deck
}
Pre 4.2
J'aime cette solution que j'ai mise en place après avoir trouvé cette page: Compréhension de liste dans Swift
Il utilise Int raw au lieu de Strings, mais évite de taper deux fois, il permet de personnaliser les plages et ne code pas en dur les valeurs brutes.
Ceci est la version 4 de Swift de ma solution d'origine mais voyez l'amélioration 4.2 ci-dessus.
enum Suit: Int {
case None
case Spade, Heart, Diamond, Club
static let allRawValues = Suit.Spade.rawValue...Suit.Club.rawValue
static let allCases = Array(allRawValues.map{ Suit(rawValue: $0)! })
}
enum Rank: Int {
case Joker
case Two, Three, Four, Five, Six
case Seven, Eight, Nine, Ten
case Jack, Queen, King, Ace
static let allRawValues = Rank.Two.rawValue...Rank.Ace.rawValue
static let allCases = Array(allRawValues.map{ Rank(rawValue: $0)! })
}
func makeDeck(withJoker: Bool = false) -> [Card] {
var deck = [Card]()
for suit in Suit.allCases {
for rank in Rank.allCases {
deck.append(Card(suit: suit, rank: rank))
}
}
if withJoker {
deck.append(Card(suit: .None, rank: .Joker))
}
return deck
}
Je me suis retrouvé en train de faire .allValues
beaucoup tout au long de mon code. J'ai finalement trouvé un moyen de simplement me conformer à un protocole Iteratable
et d'avoir une méthode rawValues()
.
protocol Iteratable {}
extension RawRepresentable where Self: RawRepresentable {
static func iterateEnum<T: Hashable>(_: T.Type) -> AnyIterator<T> {
var i = 0
return AnyIterator {
let next = withUnsafePointer(to: &i) {
$0.withMemoryRebound(to: T.self, capacity: 1) { $0.pointee }
}
if next.hashValue != i { return nil }
i += 1
return next
}
}
}
extension Iteratable where Self: RawRepresentable, Self: Hashable {
static func hashValues() -> AnyIterator<Self> {
return iterateEnum(self)
}
static func rawValues() -> [Self.RawValue] {
return hashValues().map({$0.rawValue})
}
}
// Example
enum Grocery: String, Iteratable {
case Kroger = "kroger"
case HEB = "h.e.b."
case Randalls = "randalls"
}
let groceryHashes = Grocery.hashValues() // AnyIterator<Grocery>
let groceryRawValues = Grocery.rawValues() // ["kroger", "h.e.b.", "randalls"]
EDIT: Proposition de Swift EvolutionSE-0194 Collection dérivée de cas Enum propose un niveau solution à ce problème. Nous le voyons dans Swift 4.2 et plus récent. La proposition souligne également certaines solutions de contournement qui sont similaires à certaines déjà mentionnées ici, mais il pourrait être intéressant de voir néanmoins.
Je conserverai également mon message original pour des raisons de complétude.
C'est encore une autre approche basée sur la réponse de @ Peymmankh, adaptée à Swift 3.
public protocol EnumCollection : Hashable {}
extension EnumCollection {
public static func allValues() -> [Self] {
typealias S = Self
let retVal = AnySequence { () -> AnyIterator<S> in
var raw = 0
return AnyIterator {
let current = withUnsafePointer(to: &raw) {
$0.withMemoryRebound(to: S.self, capacity: 1) { $0.pointee }
}
guard current.hashValue == raw else { return nil }
raw += 1
return current
}
}
return [S](retVal)
}
}
enum Rank: Int {
...
static let ranks = (Rank.Ace.rawValue ... Rank.King.rawValue).map{Rank(rawValue: $0)! }
}
enum Suit {
...
static let suits = [Spades, Hearts, Diamonds, Clubs]
}
struct Card {
...
static func fullDesk() -> [Card] {
var desk: [Card] = []
for suit in Suit.suits {
for rank in Rank.ranks {
desk.append(Card(rank: rank,suit: suit))
}
}
return desk
}
}
Que dis-tu de ça?
Désolé, ma réponse était spécifique à la façon dont j'ai utilisé ce message pour ce que je devais faire. Pour ceux qui trébuchent sur cette question, cherchant un moyen de trouver un cas dans une énumération, voici le moyen de le faire (nouveau dans Swift 2):
Edit: minuscule camelCase est maintenant la norme pour les valeurs Swift 3 enum
// From Apple docs: If the raw-value type is specified as String and you don’t assign values to the cases explicitly, each unassigned case is implicitly assigned a string with the same text as the name of that case.
enum Theme: String
{
case white, blue, green, lavender, grey
}
func loadTheme(theme: String)
{
// this checks the string against the raw value of each enum case (note that the check could result in a nil value, since it's an optional, which is why we introduce the if/let block
if let testTheme = Theme(rawValue: theme)
{
// testTheme is guaranteed to have an enum value at this point
self.someOtherFunction(testTheme)
}
}
Pour ceux qui s’interrogent sur l’énumération sur une énumération, les réponses données sur cette page qui incluent un var/let statique contenant un tableau de toutes les valeurs d’énum sont correctes. Le dernier exemple de code Apple pour tvOS contient exactement la même technique.
Cela étant dit, ils devraient créer un mécanisme plus pratique dans le langage (Apple, est-ce que vous écoutez?)!
Dans Swift 3, lorsque l'énum sous-jacent a {rawValue} s, vous pouvez implémenter le protocole {Strideable}. Les avantages sont qu'aucun tableau de valeurs n'est créé comme dans d'autres suggestions et que l'instruction Swift standard "for i in ..." fonctionne, ce qui donne la syntaxe Nice.
// "Int" to get rawValue, and {Strideable} so we can iterate
enum MyColorEnum : Int, Strideable {
case Red
case Green
case Blue
case Black
//-------- required by {Strideable}
typealias Stride = Int
func advanced(by n:Stride) -> MyColorEnum {
var next = self.rawValue + n
if next > MyColorEnum.Black.rawValue {
next = MyColorEnum.Black.rawValue
}
return MyColorEnum(rawValue: next)!
}
func distance(to other: MyColorEnum) -> Int {
return other.rawValue - self.rawValue
}
//-------- just for printing
func simpleDescription() -> String {
switch self {
case .Red: return "Red"
case .Green: return "Green"
case .Blue: return "Blue"
case .Black: return "Black"
}
}
}
// this is how you use it:
for i in MyColorEnum.Red ... MyColorEnum.Black {
print("ENUM: \(i)")
}
Vous pouvez essayer d'énumérer comme ça
enum Planet: String {
case Mercury
case Venus
case Earth
case Mars
static var enumerate: [Planet] {
var a: [Planet] = []
switch Planet.Mercury {
case .Mercury: a.append(.Mercury); fallthrough
case .Venus: a.append(.Venus); fallthrough
case .Earth: a.append(.Earth); fallthrough
case .Mars: a.append(.Mars)
}
return a
}
}
Planet.enumerate // [Mercury, Venus, Earth, Mars]
C'est ce que j'ai fini par aller avec; Je pense que cela établit un juste équilibre entre lisibilité et maintenabilité.
struct Card {
// ...
static func deck() -> Card[] {
var deck = Card[]()
for rank in Rank.Ace.toRaw()...Rank.King.toRaw() {
for suit in [Suit.Spades, .Hearts, .Clubs, .Diamonds] {
let card = Card(rank: Rank.fromRaw(rank)!, suit: suit)
deck.append(card)
}
}
return deck
}
let deck = Card.deck()
enum Filter: String, CaseIterable {
case salary = "Salary"
case experience = "Experience"
case technology = "Technology"
case unutilized = "Unutilized"
case unutilizedHV = "Unutilized High Value"
static let allValues = Filter.allCases.map { $0.rawValue }
}
Appeler
print(Filter.allValues)
Impressions:
["Salaire", "Expérience", "Technologie", "Inutilisé", "Haute valeur inutilisée"]
enum
représentant Int
enum Filter: Int {
case salary
case experience
case technology
case unutilized
case unutilizedHV
static let allRawValues = salary.rawValue...unutilizedHV.rawValue // First to last case
static let allValues = allRawValues.map { Filter(rawValue: $0)!.rawValue }
}
Appelez ça comme ça:
print(Filter.allValues)
Impressions:
[0, 1, 2, 3, 4]
enum
représentant String
enum Filter: Int {
case salary
case experience
case technology
case unutilized
case unutilizedHV
static let allRawValues = salary.rawValue...unutilizedHV.rawValue // First to last case
static let allValues = allRawValues.map { Filter(rawValue: $0)!.description }
}
extension Filter: CustomStringConvertible {
var description: String {
switch self {
case .salary: return "Salary"
case .experience: return "Experience"
case .technology: return "Technology"
case .unutilized: return "Unutilized"
case .unutilizedHV: return "Unutilized High Value"
}
}
}
Appeler
print(Filter.allValues)
Impressions:
["Salaire", "Expérience", "Technologie", "Inutilisé", "Haute valeur inutilisée"]
L'expérience était: EXPERIMENT
Ajoutez une méthode à la carte qui crée un jeu complet de cartes, avec une carte de chaque combinaison de rang et de couleur.
Donc, sans modifier ni améliorer le code donné autrement qu'en ajoutant la méthode (et sans utiliser des éléments qui n'ont pas encore été enseignés), j'ai proposé cette solution:
struct Card {
var rank: Rank
var suit: Suit
func simpleDescription() -> String {
return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
}
func createDeck() -> [Card] {
var deck: [Card] = []
for rank in Rank.Ace.rawValue...Rank.King.rawValue {
for suit in Suit.Spades.rawValue...Suit.Clubs.rawValue {
let card = Card(rank: Rank(rawValue: rank)!, suit: Suit(rawValue: suit)!)
//println(card.simpleDescription())
deck += [card]
}
}
return deck
}
}
let threeOfSpades = Card(rank: .Three, suit: .Spades)
let threeOfSpadesDescription = threeOfSpades.simpleDescription()
let deck = threeOfSpades.createDeck()
Tout en traitant de Swift 2.0
voici ma suggestion:
J'ai ajouté le type brut à Suit
enum
enum Suit: Int {
puis:
struct Card {
var rank: Rank
var suit: Suit
func fullDeck()-> [Card] {
var deck = [Card]()
for i in Rank.Ace.rawValue...Rank.King.rawValue {
for j in Suit.Spades.rawValue...Suit.Clubs.rawValue {
deck.append(Card(rank:Rank(rawValue: i)! , suit: Suit(rawValue: j)!))
}
}
return deck
}
}
Comme avec @Kametrixom answer here Je pense que retourner un tableau serait mieux que de retourner AnySequence, car vous pouvez avoir accès à tous les goodies d'Array tels que count, etc.
Voici la réécriture:
public protocol EnumCollection : Hashable {}
extension EnumCollection {
public static func allValues() -> [Self] {
typealias S = Self
let retVal = AnySequence { () -> AnyGenerator<S> in
var raw = 0
return AnyGenerator {
let current : Self = withUnsafePointer(&raw) { UnsafePointer($0).memory }
guard current.hashValue == raw else { return nil }
raw += 1
return current
}
}
return [S](retVal)
}
}
Je l'ai fait en utilisant la propriété calculée, qui renvoie le tableau de toutes les valeurs (grâce à cet article http://natecook.com/blog/2014/10/loopy-random-enum-ideas/ ). Cependant, il utilise également int raw-values, mais je n'ai pas besoin de répéter tous les membres de l'énumération dans une propriété distincte.
UPDATE Xcode 6.1 a un peu changé la façon d'obtenir un membre enum en utilisant une valeur brute, j'ai donc corrigé le listing. Également corrigé une petite erreur avec une première valeur brute incorrecte
enum ValidSuits:Int{
case Clubs=0, Spades, Hearts, Diamonds
func description()->String{
switch self{
case .Clubs:
return "♣︎"
case .Spades:
return "♠︎"
case .Diamonds:
return "♦︎"
case .Hearts:
return "♥︎"
}
}
static var allSuits:[ValidSuits]{
return Array(
SequenceOf {
() -> GeneratorOf<ValidSuits> in
var i=0
return GeneratorOf<ValidSuits>{
return ValidSuits(rawValue: i++)
}
}
)
}
}
Les énumérations ont les méthodes toRaw () et fromRaw (). Ainsi, si votre valeur brute est un Int, vous pouvez effectuer une itération du premier au dernier enum:
enum Suit: Int {
case Spades = 1
case Hearts, Diamonds, Clubs
func simpleDescription() -> String {
switch self {
case .Spades:
return "spades"
case .Hearts:
return "hearts"
case .Diamonds:
return "diamonds"
case .Clubs:
return "clubs"
}
}
}
for i in Suit.Spades.toRaw()...Suit.Clubs.toRaw() {
if let covertedSuit = Suit.fromRaw(i) {
let description = covertedSuit.simpleDescription()
}
}
Un des pièges est que vous devez tester les valeurs facultatives avant d'exécuter la méthode simpleDescription. Nous définissons donc d'abord converti comme suit pour notre valeur, puis définissons une constante sur conversSuit.simpleDescription ().
Ceci est un joli vieux post, de Swift 2.0. Il existe maintenant de meilleures solutions qui utilisent les nouvelles fonctionnalités de Swift 3.0: Itérer dans un Enum dans Swift 3.0
Et sur cette question, il existe une solution qui utilise une nouvelle fonctionnalité de (le pas encore publié, au moment où j'écris cette édition) Swift 4.2: Comment puis-je obtenir le compte d'un enum Swift?
Il y a beaucoup de bonnes solutions dans ce fil et d'autres, mais certaines sont très compliquées. J'aime simplifier autant que possible. Voici une solution qui peut ou peut ne pas fonctionner pour des besoins différents mais je pense que cela fonctionne bien dans la plupart des cas:
enum Number: String {
case One
case Two
case Three
case Four
case EndIndex
func nextCase () -> Number
{
switch self {
case .One:
return .Two
case .Two:
return .Three
case .Three:
return .Four
case .Four:
return .EndIndex
/*
Add all additional cases above
*/
case .EndIndex:
return .EndIndex
}
}
static var allValues: [String] {
var array: [String] = Array()
var number = Number.One
while number != Number.EndIndex {
array.append(number.rawValue)
number = number.nextCase()
}
return array
}
}
Pour itérer:
for item in Number.allValues {
print("number is: \(item)")
}
Cela ressemble à un hack, mais si vous utilisez des valeurs brutes, vous pouvez faire quelque chose comme ceci.
enum Suit: Int {
case Spades = 0, Hearts, Diamonds, Clubs
...
}
var suitIndex = 0
while var suit = Suit.fromRaw(suitIndex++) {
...
}
Voici une méthode que j'utilise pour itérer une énumération et fournir plusieurs types de valeurs d'une énumération
enum IterateEnum: Int {
case Zero
case One
case Two
case Three
case Four
case Five
case Six
case Seven
//Tuple allows multiple values to be derived from the enum case, and
//since it is using a switch with no default, if a new case is added,
//a compiler error will be returned if it doesn't have a value Tuple set
var value: (french:String, spanish:String, japanese:String) {
switch self {
case .Zero: return (french:"zéro", spanish:"cero", japanese:"nuru")
case .One: return (french:"un", spanish:"uno", japanese:"ichi")
case .Two: return (french:"deux", spanish:"dos", japanese:"ni")
case .Three: return (french:"trois", spanish:"tres", japanese:"san")
case .Four: return (french:"quatre", spanish:"cuatro", japanese:"shi")
case .Five: return (french:"cinq", spanish:"cinco", japanese:"go")
case .Six: return (french:"six", spanish:"seis", japanese:"roku")
case .Seven: return (french:"sept", spanish:"siete", japanese:"shichi")
}
}
//Used to iterate enum or otherwise access enum case by index order.
//Iterate by looping until it returns nil
static func item(index:Int) -> IterateEnum? {
return IterateEnum.init(rawValue: index)
}
static func numberFromSpanish(number:String) -> IterateEnum? {
return findItem { $0.value.spanish == number }
}
//use block to test value property to retrieve the enum case
static func findItem(predicate:((_:IterateEnum)->Bool)) -> IterateEnum? {
var enumIndex:Int = -1
var enumCase:IterateEnum?
//Iterate until item returns nil
repeat {
enumIndex += 1
enumCase = IterateEnum.item(index: enumIndex)
if let eCase = enumCase {
if predicate(eCase) {
return eCase
}
}
} while enumCase != nil
return nil
}
}
var enumIndex:Int = -1
var enumCase:IterateEnum?
//Iterate until item returns nil
repeat {
enumIndex += 1
enumCase = IterateEnum.item(index: enumIndex)
if let eCase = enumCase {
print("The number \(eCase) in french: \(eCase.value.french), spanish: \(eCase.value.spanish), japanese: \(eCase.value.japanese)")
}
} while enumCase != nil
print("Total of \(enumIndex) cases")
let number = IterateEnum.numberFromSpanish(number: "siete")
print("siete in japanese: \((number?.value.japanese ?? "Unknown"))")
C'est la sortie:
Le nombre zéro en français: zéro, espagnol: cero, japonais: nuru
Le numéro un en français: un, espagnol: uno, japonais: ichi
Le nombre Deux en français: deux, espagnol: dos, japonais: ni
Le nombre Trois en français: trois, espagnol: tres, japonais: san
Le nombre Quatre en français: quatre, espagnol: cuatro, japonais: shi
Le nombre Cinq en français: cinq, espagnol: cinco, japonais: go
Le nombre Six en français: six, espagnol: seis, japonais: roku
Le nombre Sept en français: septembre, espagnol: siete, japonais: shichi
Total de 8 cas
siete en japonais: shichi
METTRE &AGRAVE; JOUR
J'ai récemment créé un protocole pour gérer l'énumération. Le protocole nécessite une énumération avec une valeur brute Int:
protocol EnumIteration {
//Used to iterate enum or otherwise access enum case by index order. Iterate by looping until it returns nil
static func item(index:Int) -> Self?
static func iterate(item:((index:Int, enumCase:Self)->()), completion:(()->())?) {
static func findItem(predicate:((enumCase:Self)->Bool)) -> Self?
static func count() -> Int
}
extension EnumIteration where Self: RawRepresentable, Self.RawValue == Int {
//Used to iterate enum or otherwise access enum case by index order. Iterate by looping until it returns nil
static func item(index:Int) -> Self? {
return Self.init(rawValue: index)
}
static func iterate(item:((index:Int, enumCase:Self)->()), completion:(()->())?) {
var enumIndex:Int = -1
var enumCase:Self?
//Iterate until item returns nil
repeat {
enumIndex += 1
enumCase = Self.item(enumIndex)
if let eCase = enumCase {
item(index: enumIndex, enumCase: eCase)
}
} while enumCase != nil
completion?()
}
static func findItem(predicate:((enumCase:Self)->Bool)) -> Self? {
var enumIndex:Int = -1
var enumCase:Self?
//Iterate until item returns nil
repeat {
enumIndex += 1
enumCase = Self.item(enumIndex)
if let eCase = enumCase {
if predicate(enumCase:eCase) {
return eCase
}
}
} while enumCase != nil
return nil
}
static func count() -> Int {
var enumIndex:Int = -1
var enumCase:Self?
//Iterate until item returns nil
repeat {
enumIndex += 1
enumCase = Self.item(enumIndex)
} while enumCase != nil
//last enumIndex (when enumCase == nil) is equal to the enum count
return enumIndex
}
}
Voici mon approche suggérée. Ce n'est pas complètement satisfaisant (je suis très novice dans Swift et OOP!) Mais peut-être que quelqu'un peut l'affiner. L'idée est de faire en sorte que chaque énumération fournisse ses propres informations de plage sous forme de propriétés .first et .last. Il ajoute juste deux lignes de code à chaque énumération: toujours un peu codé en dur, mais au moins, il ne duplique pas l’ensemble. Cela nécessite de modifier le Suit enum pour qu'il soit un Int comme le Rank est enum, au lieu de non typé.
Plutôt que de faire écho à l'ensemble de la solution, voici le code que j'ai ajouté à Rank enum, quelque part après les instructions case (Suit enum est similaire):
var first: Int { return Ace.toRaw() }
var last: Int { return King.toRaw() }
et la boucle que j'ai utilisée pour construire le deck sous la forme d'un tableau de String. (La définition du problème ne précisait pas comment le jeu devait être structuré.)
func createDeck() -> [String] {
var deck: [String] = []
var card: String
for r in Rank.Ace.first...Rank.Ace.last {
for s in Suit.Hearts.first...Suit.Hearts.last {
card = Rank.simpleDescription( Rank.fromRaw(r)!)() + " of " + Suit.simpleDescription( Suit.fromRaw(s)!)()
deck.append( card)
}
}
return deck
}
Ce n'est pas satisfaisant car les propriétés sont associées à un élément plutôt qu'à l'énum. Mais cela ajoute de la clarté aux boucles "pour". J'aimerais qu'il dise Rank.first au lieu de Rank.Ace.first. Cela fonctionne (avec n'importe quel élément), mais c'est moche. Quelqu'un peut-il montrer comment élever cela au niveau enum?
Et pour que cela fonctionne, j'ai sorti la méthode createDeck de la structure Card ... Je ne pouvais pas trouver comment obtenir un tableau [String] renvoyé de cette structure, et cela semble de toute façon un mauvais endroit pour mettre une telle méthode.
Une autre solution:
enum Suit: String {
case spades = "♠"
case hearts = "♥"
case diamonds = "♦"
case clubs = "♣"
static var count: Int {
return 4
}
init(index: Int) {
switch index {
case 0: self = .spades
case 1: self = .hearts
case 2: self = .diamonds
default: self = .clubs
}
}
}
for i in 0..<Suit.count {
print(Suit(index: i).rawValue)
}
enum Rank: Int
{
case Ace = 0
case Two, Three, Four, Five, Six, Seve, Eight, Nine, Ten
case Jack, Queen, King
case Count
}
enum Suit : Int
{
case Spades = 0
case Hearts, Diamonds, Clubs
case Count
}
struct Card
{
var rank:Rank
var suit:Suit
}
class Test
{
func makeDeck() -> Card[]
{
let suitsCount:Int = Suit.Count.toRaw()
let rankCount:Int = Rank.Count.toRaw()
let repeatedCard:Card = Card(rank:Rank.Ace, suit:Suit.Spades)
let deck:Card[] = Card[](count:suitsCount*rankCount, repeatedValue:repeatedCard)
for i:Int in 0..rankCount
{
for j:Int in 0..suitsCount
{
deck[i*suitsCount+j] = Card(rank: Rank.fromRaw(i)!, suit: Suit.fromRaw(j)!)
}
}
return deck
}
}
Basé sur la réponse de Rick: c'est 5 fois plus rapide
(Amélioration de la réponse de Karthik Kumar)
Cette solution utilise le compilateur pour vous garantir de ne manquer aucun cas.
enum Suit: String {
case spades = "♠"
case hearts = "♥"
case diamonds = "♦"
case clubs = "♣"
static var enumerate: [Suit] {
switch Suit.spades {
// make sure the two lines are identical ^_^
case .spades, .hearts, .diamonds, .clubs:
return [.spades, .hearts, .diamonds, .clubs]
}
}
}
Il existe une méthode intelligente et frustrante, car elle illustre la différence entre les deux types d’énums différents.
Essaye ça:
func makeDeck() -> Card[] {
var deck: Card[] = []
var suits: Suit[] = [.Hearts, .Diamonds, .Clubs, .Spades]
for i in 1...13 {
for suit in suits {
deck += Card(rank: Rank.fromRaw(i)!, suit: suit)
}
}
return deck
}
L’accord est qu’une énumération adossée à des nombres (valeurs brutes) est explicitement commandée, alors qu’une énumération qui n’est pas adossée à des chiffres est explicitement non ordonnée.
Par exemple. lorsque nous donnons aux nombres des valeurs enum, le langage est assez rusé pour comprendre dans quel ordre se trouvent les nombres ... Si, par contre, nous ne donnons aucun ordre, nous essayons de parcourir les valeurs du langage. lève les mains en l'air et va "oui, mais lequel voulez-vous y aller en premier ???"
Les autres langues pouvant effectuer cette opération (itération sur des énumérations non ordonnées) peuvent être les mêmes où tout est «caché», en réalité une carte ou un dictionnaire, et vous pouvez effectuer une itération sur les clés d’une carte, qu’il y ait ou non un ordre logique.
Le truc est donc de lui fournir quelque chose qui est explicitement commandé, dans ce cas des instances des combinaisons dans un tableau dans l'ordre que nous voulons. Dès que vous donnez cela, Swift est comme "pourquoi vous ne l'avez pas dit en premier lieu?"
L'autre astuce consiste à utiliser l'opérateur de forçage sur la fonction fromRaw. Cela illustre un autre «casse-tête» concernant les énumérations, selon lequel la plage de valeurs possibles à transmettre est souvent plus grande que la plage d'énums. Par exemple, si nous disons Rank.fromRaw (60), aucune valeur ne sera renvoyée. Nous utilisons donc la fonctionnalité optional de la langue, et nous commencerons bientôt à utiliser des options, ce qui sera forcé. (Ou alternativement la construction if let qui me semble encore un peu bizarre)
Solution Swift 5: La solution dans Swift 5 est assez simple:
enum Suit: String, CaseIterable {
case spades = "♠"
case hearts = "♥"
case diamonds = "♦"
case clubs = "♣"
}
// then access the cases like this:
for suitKey in LocalizationKey.allCases {
print(suitKey)
}
J'ai utilisé la méthode ci-dessous, l'hypothèse est que je sais quelle est la dernière valeur de l'en-tête Rank et que tous les rangs ont des valeurs incrémentielles après l'As
Je préfère cette façon comme c'est propre et petit, facile à comprendre
func cardDeck() -> Card[] {
var cards: Card[] = []
let minRank = Rank.Ace.toRaw()
let maxRank = Rank.King.toRaw()
for rank in minRank...maxRank {
if var convertedRank: Rank = Rank.fromRaw(rank) {
cards.append(Card(rank: convertedRank, suite: Suite.Clubs))
cards.append(Card(rank: convertedRank, suite: Suite.Diamonds))
cards.append(Card(rank: convertedRank, suite: Suite.Hearts))
cards.append(Card(rank: convertedRank, suite: Suite.Spades))
}
}
return cards
}
Parfois, vous pouvez traiter un type énuméré avec un type entier brut sous-jacent qui change tout au long du cycle de développement du logiciel. Voici un exemple qui fonctionne bien pour ce cas:
public class MyClassThatLoadsTexturesEtc
{
//...
// Colors used for gems and sectors.
public enum Color: Int
{
// Colors arranged in order of the spectrum.
case First = 0
case Red, Orange, Yellow, Green, Blue, Purple, Pink
// --> Add more colors here, between the first and last markers.
case Last
}
//...
public func preloadGems()
{
// Preload all gems.
for i in (Color.First.toRaw() + 1) ..< (Color.Last.toRaw())
{
let color = Color.fromRaw(i)!
loadColoredTextures(forKey: color)
}
}
//...
}
Il m'a fallu un peu plus qu'une seule méthode dans la structure, comme le récit le livre Swift, mais j'ai configuré les fonctions suivantes dans l'énum. J'aurais utilisé un protocole mais je ne suis pas sûr de savoir pourquoi mais le fait que le rang soit défini comme int le perturbe
enum Rank: Int {
case Ace = 1
case Two, Three, Four, Five, Six, Seve, Eight, Nine, Ten
case Jack, Queen, King
func simpleDescription() -> String {
switch self{
case .Ace:
return "ace"
case .Jack:
return "jack"
case .Queen:
return "Queen"
case .King:
return "King"
default:
return String(self.toRaw())
}
}
mutating func next() -> Rank {
var rank = self
var rawrank = rank.toRaw()
var nrank:Rank = self
rawrank = rawrank + 1
if let newRank = Rank.fromRaw(rawrank) {
println("\(newRank.simpleDescription())")
nrank = newRank
} else {
return self
}
return nrank
}
}
enum Suit {
case Spades, Hearts, Diamonds, Clubs
func color() -> String {
switch self{
case .Spades, .Clubs:
return "black"
default:
return "red"
}
}
func simpleDescription() -> String {
switch self{
case .Spades:
return "spades"
case .Hearts:
return "hearts"
case .Diamonds:
return "diamonds"
case .Clubs:
return "clubs"
}
}
mutating func next() -> Suit {
switch self{
case .Spades:
return Hearts
case .Hearts:
return Diamonds
case .Diamonds:
return Clubs
case .Clubs:
return Spades
}
}
}
struct Card {
var rank:Rank
var suit:Suit
func deck() -> Card[] {
var tRank = self.rank
var tSuit = self.suit
let tcards = 52 // we start from 0
var cards: Card[] = []
for i in 0..tcards{
var card = Card(rank: tRank, suit: tSuit)
cards.append(card)
tRank = tRank.next()
tSuit = tSuit.next()
}
return cards
}
func simpleDescription() -> String {
return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
}
}
var card = Card(rank: .Ace, suit: .Spades)
var deck = card.deck()
j'espère que cela aide en gros, j'ai utilisé un peu de connaissances générales, mais cela peut être facilement corrigé en multipliant les suites par rang Note différente pour gagner du temps, j'ai utilisé des valeurs brutes de rangs. Vous pouvez faire la même chose pour les costumes si vous le souhaitez, mais l'exemple ne le contient pas.
J'ai ajouté la fonction count (), et itère les valeurs:
public enum MetricType : Int {
case mvps = 0
case allNBA = 1
case championshipRings = 2
case finalAppearances = 3
case gamesPlayed = 4
case ppg = 5
static func count() -> Int {
return (ppg.rawValue) + 1
}
static var allValues: [MetricType] {
var array: [MetricType] = Array()
var item : MetricType = MetricType.mvps
while item.rawValue < MetricType.count() {
array.append(item)
item = MetricType(rawValue: (item.rawValue + 1))!
}
return array
}
}
Ma solution est de déclarer un tableau avec toutes les possibilités enum, afin de pouvoir les parcourir toutes.
//Function inside struct Card
static func generateFullDeck() -> [Card] {
let allRanks = [Rank.Ace, Rank.Two, Rank.Three, Rank.Four, Rank.Five, Rank.Six, Rank.Seven, Rank.Eight, Rank.Nine, Rank.Ten, Rank.Jack, Rank.Queen, Rank.King]
let allSuits = [Suit.Hearts, Suit.Diamonds, Suit.Clubs, Suit.Spades]
var myFullDeck: [Card] = []
for myRank in allRanks {
for mySuit in allSuits {
myFullDeck.append(Card(rank: myRank, suit: mySuit))
}
}
return myFullDeck
}
//actual use:
let aFullDeck = Card.generateFullDeck() //Generate the desired full deck
var allDesc: [String] = []
for aCard in aFullDeck {
println(aCard.simpleDescription()) //You'll see all the results in playground
}
J'ai trouvé un moyen un peu hacky, mais beaucoup plus sûr de le faire, qui ne nécessite pas de saisir les valeurs deux fois ou de référencer la mémoire des valeurs enum, ce qui rend très peu probable la rupture.
Fondamentalement, au lieu d'utiliser une énumération, créez une structure avec une seule instance et créez toutes les constantes de valeurs énumérées. Les variables peuvent ensuite être interrogées à l’aide de Mirror
public struct Suit{
// the values
let spades = "♠"
let hearts = "♥"
let diamonds = "♦"
let clubs = "♣"
// make a single instance of the Suit struct, Suit.instance
struct SStruct{static var instance: Suit = Suit()}
static var instance : Suit{
get{return SStruct.instance}
set{SStruct.instance = newValue}
}
// an array with all of the raw values
static var allValues: [String]{
var values = [String]()
let mirror = Mirror(reflecting: Suit.instance)
for (_, v) in mirror.children{
guard let suit = v as? String else{continue}
values.append(suit)
}
return values
}
}
Si vous utilisez cette méthode, pour obtenir une valeur unique, vous devez utiliser Suit.instance.clubs
ou Suit.instance.spades
.
Mais tout cela est si ennuyeux ... Faisons des choses qui font que cela ressemble davantage à une véritable énorme!
public struct SuitType{
// store multiple things for each suit
let spades = Suit("♠", order: 4)
let hearts = Suit("♥", order: 3)
let diamonds = Suit("♦", order: 2)
let clubs = Suit("♣", order: 1)
struct SStruct{static var instance: SuitType = SuitType()}
static var instance : SuitType{
get{return SStruct.instance}
set{SStruct.instance = newValue}
}
// a dictionary mapping the raw values to the values
static var allValuesDictionary: [String : Suit]{
var values = [String : Suit]()
let mirror = Mirror(reflecting: SuitType.instance)
for (_, v) in mirror.children{
guard let suit = v as? Suit else{continue}
values[suit.rawValue] = suit
}
return values
}
}
public struct Suit: RawRepresentable, Hashable{
public var rawValue: String
public typealias RawValue = String
public var hashValue: Int{
// find some integer that can be used to uniquely identify
// each value. In this case, we could have used the order
// variable because it is a unique value, yet to make this
// apply to more cases, the hash table address of rawValue
// will be returned, which should work in almost all cases
//
// you could also add a hashValue parameter to init() and
// give each suit a different hash value
return rawValue.hash
}
public var order: Int
public init(_ value: String, order: Int){
self.rawValue = value
self.order = order
}
// an array of all of the Suit values
static var allValues: [Suit]{
var values = [Suit]()
let mirror = Mirror(reflecting: SuitType.instance)
for (_, v) in mirror.children{
guard let suit = v as? Suit else{continue}
values.append(suit)
}
return values
}
// allows for using Suit(rawValue: "♦"), like a normal enum
public init?(rawValue: String){
// get the Suit from allValuesDictionary in SuitType, or return nil if that raw value doesn't exist
guard let suit = SuitType.allValuesDictionary[rawValue] else{return nil}
// initialize a new Suit with the same properties as that with the same raw value
self.init(suit.rawValue, order: suit.order)
}
}
Vous pouvez maintenant faire des choses comme
let allSuits: [Suit] = Suit.allValues
ou
for suit in Suit.allValues{
print("The suit \(suit.rawValue) has the order \(suit.order)")
}
Cependant, pour en obtenir un, vous devez toujours utiliser SuitType.instance.spades
ou SuitType.instance.hearts
. Pour rendre cela un peu plus intuitif, vous pouvez ajouter du code à Suit
qui vous permet d’utiliser Suit.type.*
au lieu de SuitType.instance.*
public struct Suit: RawRepresentable, Hashable{
// ...your code...
static var type = SuitType.instance
// ...more of your code...
}
Vous pouvez maintenant utiliser Suit.type.diamonds
au lieu de SuitType.instance.diamonds
ou Suit.type.clubs
au lieu de SuitType.instance.clubs
Adapter la réponse de @ rintaro à Swift 3 dans laquelle rintaro:
iterateEnum()
pour itérer des cas pour des types enum arbitrairesSwift3
func iterateEnum<T: Hashable>(_: T.Type) -> AnyGenerator<T> {
var i = 0
return AnyGenerator {
let next = withUnsafePointer(&i) { UnsafePointer<T>($0).memory }
let value : T?
if next.hashValue == i {
value = next
} else {
value = nil
}
i = i + 1
return value
}
}