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.