모든 열거 형 값을 배열로 가져 오는 방법


101

다음 열거 형이 있습니다.

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

모든 원시 값을 문자열 배열로 가져와야 ["Pending", "On Hold", "Done"]합니다.

이 메서드를 열거 형에 추가했습니다.

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

하지만 다음과 같은 오류가 발생합니다.

'(()-> _)'유형의 인수 목록을 허용하는 'GeneratorOf'유형에 대한 이니셜 라이저를 찾을 수 없습니다.

이 작업을 수행하는 더 쉽고, 더 좋고, 더 우아한 방법이 있습니까?


2
[EstimateItemStatus] = [.Pending, .Onhold,되는 .done] : 당신은하자 배열과 같은 배열을 만들 수 있습니다
크리스티안 Delivuk

1
@KristijanDelivuk이 기능을 열거 형 자체에 추가하고 싶습니다. 따라서 열거 형에 다른 값을 추가하면 코드베이스의 다른 위치에 가서 추가 할 필요가 없습니다.
ISURU


여기에서 참조 할 수있는 답변이 있습니다. stackoverflow.com/a/48960126/5372480
MSimic

답변:


149

Swift 4.2 (Xcode 10) 이상

있다 CaseIterable프로토콜 :

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의 경우

아니요, enum어떤 값이 포함되어 있는지를 쿼리 할 수 ​​없습니다 . 이 기사를 참조 하십시오 . 가지고있는 모든 값을 나열하는 배열을 정의해야합니다. 또한 " 모든 열거 형 값을 배열로 가져 오는 방법 "에서 Frank Valbuena의 솔루션을 확인하십시오 .

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

이 답변을 참조하십시오 : Swift 3 코드를 포함하여 stackoverflow.com/a/28341290/8047 .
Dan Rosenstark

3
allValues ​​부분에 대해 찬성하지만 열거 형이 String 유형이지만 Int로 초기화되는 것에 대해 어떻게 생각할지 모르겠습니다.
Tyress

첫 번째 링크가 끊어졌지만 이제 exceptionshub.com/… 에있는 것으로 보입니다 .
The Tin Man

39

Swift 4.2CaseIterable

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

을 준수하면 다음 enum과 같은 경우 에서 배열을 얻을 수 있습니다.

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

27

열거 형에 CaseIterable 프로토콜을 추가 합니다.

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

용법:

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

17

적어도 컴파일 타임에 안전한 또 다른 방법이 있습니다.

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

이것은 모든 enum 유형 (RawRepresentable 여부)에 대해 작동하고 새 케이스를 추가하면 컴파일러 오류가 발생하여이를 최신 상태로 유지해야합니다.


1
비 정통적이지만 작동하며 열거 형 케이스를 수정하면 경고합니다. 영리한 솔루션!
Chuck Krutsinger 2018

12

어딘가에서이 코드를 찾았습니다.

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

사용하다:

enum YourEnum: EnumCollection { //code }

YourEnum.cases()

YourEnum에서 사례 목록 반환


훌륭한 솔루션처럼 보이지만 Swift 4에서 꽤 많은 컴파일 오류가 있습니다.
Isuru

1
"어딘가"는 theswiftdev.com/2017/10/12/swift-enum-all-values (다른 것 중에?) 일 수 있습니다. 블로거는 CoreKit을 인정 합니다 .
AmitaiB

5
이것은 XCode 10 (Swift 버전에 관계없이)에서 중단됩니다. enum의 hashValue가 더 이상 증분이 아니라 무작위로되어 메커니즘을 깨뜨리기 때문입니다. 이를위한 새로운 방법은 Swift 4.2로 업그레이드하고 CaseIterable을 사용하는 것입니다
Yasper

8

기능적 목적으로 목록을 얻으려면 EnumName.allCases배열을 반환하는 표현식 을 사용하십시오.

EnumName.allCases.map{$0.rawValue} 

주어진 문자열 목록을 제공합니다. EnumName: String, CaseIterable

참고 : allCases대신 AllCases().


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

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

[ "보류", "보류", "완료"]


2

Swift 5 업데이트

내가 찾은 가장 쉬운 해결책 .allCases은 확장되는 열거 형 에 사용 하는 것입니다.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
        }
    }
}

.allCases모든 CaseIterable열거 형 Collection에서 해당 요소의를 반환합니다 .

var myEnumArray = EstimateItemStatus.allCases

CaseIterable 에 대한 자세한 정보


description ()을 구현할 필요가 없습니다. 예를 들어 각 케이스를 문자열과 동일시하면 각각 case OnHold = "On Hold"의 원시 값이됩니다.
pnizzle

@pnizzle 나는 그것이 원래 질문에 있었기 때문에 거기에 있습니다.
Christopher Larsen

1

Swift 2의 경우

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

그것을 사용하려면 :

arrayEnum(MyEnumClass.self)

왜 요소 hashValue0..n될까요?
NRitH

1

시퀀스 에서 영감을 얻은 후 몇 시간 동안 시도 n 오류. 마침내 Xcode 9.1에서 편안하고 아름다운 Swift 4 방식을 얻었습니다.

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

용법:

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

산출:

Pending
On Hold
Done

1

당신이 사용할 수있는

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

좋은! Swift 3.2에서 4.1로 업그레이드 한 후 이것이 제가 사용한 솔루션이었습니다. 원래 AnyItertor <Self> 선언이있었습니다. 귀하의 솔루션은 훨씬 깨끗하고 읽기 쉽습니다. 감사!
Nick N

2
여기에 하나의 코드 결함이 있습니다. 케이스의 첫 번째 항목이 누락되었습니다. var index = 1을 var index = 0으로 변경
Nick N

0

열거 형이 증분이고 숫자와 연결된 경우 다음과 같이 열거 형 값에 매핑하는 숫자 범위를 사용할 수 있습니다.

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

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

이것은 문자열이나 숫자 이외의 다른 것과 관련된 열거 형에서는 잘 작동하지 않지만 그 경우에는 훌륭하게 작동합니다!


0

allValues를 만들기위한 열거 형 확장입니다.

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

이 코드는 OP 문제에 대한 해결책을 제공 할 수 있지만이 코드가 질문에 대한 답변 이유 및 / 또는 방법에 대한 추가 컨텍스트를 제공하는 것이 좋습니다. 유사한 문제를 겪고있는 미래의 시청자는 솔루션이면의 이유를 이해할 수 없기 때문에 코드 전용 답변은 일반적으로 장기적으로 쓸모가 없습니다.
E. Zeytinci
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.