Bir dizi olarak tüm enum değerleri nasıl elde edilir


105

Aşağıdaki numaraya sahibim.

enum EstimateItemStatus: Printable {
    case Pending
    case OnHold
    case Done

    var description: String {
        switch self {
        case .Pending: return "Pending"
        case .OnHold: return "On Hold"
        case .Done: return "Done"
        }
    }

    init?(id : Int) {
        switch id {
        case 1:
            self = .Pending
        case 2:
            self = .OnHold
        case 3:
            self = .Done
        default:
            return nil
        }
    }
}

Tüm ham değerleri bir dizi dizisi olarak almam gerekiyor (böyle ["Pending", "On Hold", "Done"]).

Bu yöntemi numaralandırmaya ekledim.

func toArray() -> [String] {
    var n = 1
    return Array(
        GeneratorOf<EstimateItemStatus> {
            return EstimateItemStatus(id: n++)!.description
        }
    )
}

Ama şu hatayı alıyorum.

'(() -> _)' türünde bir bağımsız değişken listesini kabul eden 'GeneratorOf' türü için bir başlatıcı bulunamıyor

Bunu yapmanın daha kolay, daha iyi veya daha zarif bir yolu var mı?


2
let array gibi bir dizi oluşturabilirsiniz: [EstimateItemStatus] = [.Pending, .Onhold, .Done]
— Kristijan Delivuk

1
@KristijanDelivuk Bu işlevselliği numaranın kendisine eklemek istiyorum. Bu nedenle, sıralamaya başka bir değer katarsam, kod tabanlarının diğer yerlerine gidip her yere eklemem gerekmez.
— Isuru


Burada başvurabileceğiniz bir cevabım var stackoverflow.com/a/48960126/5372480
— MSimic

Yanıtlar:


158

Swift 4.2 (Xcode 10) ve sonrası için

Bir CaseIterableprotokol var:

enum EstimateItemStatus: String, CaseIterable {
    case pending = "Pending"
    case onHold = "OnHold"
    case done = "Done"

    init?(id : Int) {
        switch id {
        case 1: self = .pending
        case 2: self = .onHold
        case 3: self = .done
        default: return nil
        }
    }
}

for value in EstimateItemStatus.allCases {
    print(value)
}

Swift <4.2 için

Hayır, enumhangi değerleri içerdiğini sorgulayamazsınız . Bkz bu yazıyı . Sahip olduğunuz tüm değerleri listeleyen bir dizi tanımlamalısınız. Ayrıca Frank Valbuena'nın " Tüm enum değerleri bir dizi olarak nasıl elde edilir" konusundaki çözümüne bakın .

enum EstimateItemStatus: String {
    case Pending = "Pending"
    case OnHold = "OnHold"
    case Done = "Done"

    static let allValues = [Pending, OnHold, Done]

    init?(id : Int) {
        switch id {
        case 1:
            self = .Pending
        case 2:
            self = .OnHold
        case 3:
            self = .Done
        default:
            return nil
        }
    }
}

for value in EstimateItemStatus.allValues {
    print(value)
}

Şu yanıta bakın: Swift 3 kodu dahil stackoverflow.com/a/28341290/8047 .
— Dan Rosenstark

3
AllValues ​​bölümü için yukarı oylama, ancak bir enum türünde olan ancak Int ile başlatılan bir enum hakkında ne hissedileceğinden emin değil.
— Tyress

İlk bağlantı koptu, ancak şimdi istisnai_shub.com/… adresinde görünüyor .
— Teneke Adam

41

Swift 4.2 , adlı yeni bir protokol sunarCaseIterable

enum Fruit : CaseIterable {
    case apple , apricot , orange, lemon
}

uyduğunuzda, bunun enumgibi durumlardan bir dizi elde edebilirsiniz.

for fruit in Fruit.allCases {
    print("I like eating \(fruit).")
}

28

Numaralandırmaya CaseIterable protokolünü ekleyin :

enum EstimateItemStatus: String, CaseIterable {
    case pending = "Pending"
    case onHold = "OnHold"
    case done = "Done"
}

Kullanım:

let values: [String] = EstimateItemStatus.allCases.map { $0.rawValue }
//["Pending", "OnHold", "Done"]

17

En azından derleme zamanında güvenli olmanın başka bir yolu var:

enum MyEnum {
    case case1
    case case2
    case case3
}

extension MyEnum {
    static var allValues: [MyEnum] {
        var allValues: [MyEnum] = []
        switch (MyEnum.case1) {
        case .case1: allValues.append(.case1); fallthrough
        case .case2: allValues.append(.case2); fallthrough
        case .case3: allValues.append(.case3)
        }
        return allValues
    }
}

Bunun herhangi bir enum türü (RawRepresentable veya değil) için işe yaradığına dikkat edin ve ayrıca yeni bir vaka eklerseniz, iyi olan bir derleyici hatası alacaksınız çünkü sizi bunu güncellemeye zorlayacaktır.


1
Alışılmışın dışında, ancak çalışır ve numaralandırma durumlarını değiştirirseniz sizi uyarır. Akıllı çözüm!
— Chuck Krutsinger

12

Bu kodu bir yerde buldum:

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

Kullanım:

enum YourEnum: EnumCollection { //code }

YourEnum.cases()

YourEnum'daki vakaların listesini döndür


Harika bir çözüm gibi görünüyor, ancak Swift 4'te epeyce derleme hatası var.
— Isuru

1
"Bir yer" şu olabilir: theswiftdev.com/2017/10/12/swift-enum-all-values (diğerleri arasında?). Blog yazarı CoreKit'e güveniyor .
— AmitaiB

5
Bu, XCode 10'da (Swift sürümünden bağımsız olarak) kırılır, çünkü bir numaralamanın hashValue'si artık artımlı değil rastgele olup, mekanizmayı bozar. Bunu yapmanın yeni yolu, Swift 4.2'ye yükseltmek ve CaseIterable'ı kullanmak
— Yasper

11
enum EstimateItemStatus: String, CaseIterable {
  case pending = "Pending"
  case onHold = "OnHold"
  case done = "Done"

  static var statusList: [String] {
    return EstimateItemStatus.allCases.map { $0.rawValue }
  }
}

["Beklemede", "Beklemede", "Bitti"]


9

İşlevsel amaçlarla bir liste almak için, EnumName.allCasesbir dizi döndüren ifadeyi kullanın, örn.

EnumName.allCases.map{$0.rawValue} 

size bir Dizeler listesi verecektir. EnumName: String, CaseIterable

Not: allCasesyerine kullanın AllCases().


2

Swift 5 Güncellemesi

Bulduğum en kolay çözüm, .allCasesgenişleyen bir enum üzerinde kullanmaktır .CaseIterable

enum EstimateItemStatus: CaseIterable {
    case Pending
    case OnHold
    case Done

    var description: String {
        switch self {
        case .Pending: return "Pending"
        case .OnHold: return "On Hold"
        case .Done: return "Done"
        }
    }

    init?(id : Int) {
        switch id {
        case 1:
            self = .Pending
        case 2:
            self = .OnHold
        case 3:
            self = .Done
        default:
            return nil
        }
    }
}

.allCasesherhangi bir CaseIterableenum Collection, o öğenin a değerini döndürür .

var myEnumArray = EstimateItemStatus.allCases

CaseIterable hakkında daha fazla bilgi


Description () uygulamaya gerek yoktur. Sadece her durumu dizeye eşitleyin, örneğin case OnHold = "On Hold", bu her biri için ham değer haline gelir.
— pnizzle

@pnizzle Biliyorum, orjinal soruda olduğu için orada.
— Christopher Larsen

1

Swift 2 için

// Found http://stackoverflow.com/questions/24007461/how-to-enumerate-an-enum-with-string-type
func iterateEnum<T where T: Hashable, T: RawRepresentable>(_: T.Type) -> AnyGenerator<T> {
    var i = 0
    return AnyGenerator {
        let next = withUnsafePointer(&i) {
            UnsafePointer<T>($0).memory
        }
        if next.hashValue == i {
            i += 1
            return next
        } else {
            return nil
        }
    }
}

func arrayEnum<T where T: Hashable, T: RawRepresentable>(type: T.Type) -> [T]{
    return Array(iterateEnum(type))
}

Kullanmak için:

arrayEnum(MyEnumClass.self)

Neden unsurlar olur hashValueolmak 0..n?
— NRitH

1

Esinlenerek sonra Dizi ve denemede n hataların saat. Sonunda Xcode 9.1'de bu rahat ve güzel Swift 4 yolunu aldım:

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

extension EnumSequenceElement {
    func distance(to other: Self) -> Int {
        return other.rawValue - rawValue
    }

    func advanced(by n: Int) -> Self {
        return Self(rawValue: n + rawValue) ?? self
    }
}

struct EnumSequence<T: EnumSequenceElement>: Sequence, IteratorProtocol {
    typealias Element = T

    var current: Element? = T.init(rawValue: 0)

    mutating func next() -> Element? {
        defer {
            if let current = current {
                self.current = T.init(rawValue: current.rawValue + 1)
            }
        }
        return current
    }
}

Kullanım:

enum EstimateItemStatus: Int, EnumSequenceElement, CustomStringConvertible {
    case Pending
    case OnHold
    case Done

    var description: String {
        switch self {
        case .Pending:
            return "Pending"
        case .OnHold:
            return "On Hold"
        case .Done:
            return "Done"
        }
    }
}

for status in EnumSequence<EstimateItemStatus>() {
    print(status)
}
// Or by countable range iteration
for status: EstimateItemStatus in .Pending ... .Done {
    print(status)
}

Çıktı:

Pending
On Hold
Done

1

Kullanabilirsiniz

enum Status: Int{
    case a
    case b
    case c

}

extension RawRepresentable where Self.RawValue == Int {

    static var values: [Self] {
        var values: [Self] = []
        var index = 1
        while let element = self.init(rawValue: index) {
            values.append(element)
            index += 1
        }
        return values
    }
}


Status.values.forEach { (st) in
    print(st)
}

Güzel! Swift 3.2'den 4.1'e yükselttikten sonra bu, kullandığım bir çözümdü. Başlangıçta AnyItertor <Self> bildirimleri vardı. Çözümünüz çok daha temiz ve okunması daha kolaydı. Teşekkürler!
— Nick N

2
Burada bir kod hatası var. Davadaki ilk maddeyi kaçırıyor. Var index = 1'i var index = 0 olarak değiştirin
— Nick N

0

Numaranız artımlıysa ve sayılarla ilişkiliyse, değerleri sıralamak için eşlediğiniz sayı aralığını şu şekilde kullanabilirsiniz:

// Swift 3
enum EstimateItemStatus: Int {
    case pending = 1,
    onHold
    done
}

let estimateItemStatusValues: [EstimateItemStatus?] = (EstimateItemStatus.pending.rawValue...EstimateItemStatus.done.rawValue).map { EstimateItemStatus(rawValue: $0) }

Bu, dizelerle veya sayılardan başka herhangi bir şeyle ilişkili numaralandırmalarla pek işe yaramaz, ancak durum buysa harika çalışıyor!


0

AllValues ​​oluşturmak için bir enum üzerinde uzantı.

extension RawRepresentable where Self: CaseIterable {
      static var allValues: [Self.RawValue] {
        return self.allCases.map { $0.rawValue}
      }
    }

Bu kod, OP'nin sorununa bir çözüm sağlayabilirken, bu kodun soruyu neden ve / veya nasıl yanıtladığına ilişkin ek bağlam sağlamanız şiddetle tavsiye edilir. Yalnızca kod yanıtları genellikle uzun vadede işe yaramaz hale gelir çünkü gelecekte benzer sorunları yaşayan izleyiciler çözümün arkasındaki mantığı anlayamazlar.
— E. Zeytinci
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.