web-dev-qa-db-ja.com

Swiftで列挙値の名前を取得する方法は?

生のInteger値を持つ列挙型がある場合:

enum City: Int {
  case Melbourne = 1, Chelyabinsk, Bursa
}

let city = City.Melbourne

city値を文字列Melbourneに変換するにはどうすればよいですか?この種の型名のイントロスペクションは言語で利用できますか?

次のようなもの(このコードは機能しません):

println("Your city is \(city.magicFunction)")
> Your city is Melbourne
141
Evgenii

Xcode 7ベータ5では、デフォルトでprint(_:)を使用して型名と列挙型のケースを印刷するか、Stringinit(_:)初期化子または文字列補間構文を使用してStringに変換できます。あなたの例では:

enum City: Int {
    case Melbourne = 1, Chelyabinsk, Bursa
}
let city = City.Melbourne

print(city)
// prints "Melbourne"

let cityName = "\(city)"   // or `let cityName = String(city)`
// cityName contains "Melbourne"

そのため、各ケースを切り替えて文字列リテラルを返す便利な関数を定義および保守する必要がなくなりました。さらに、未加工の値のタイプが指定されていない場合でも、これはすべての列挙に対して自動的に機能します。

debugPrint(_:)およびString(reflecting:)は、完全修飾名に使用できます。

debugPrint(city)
// prints "App.City.Melbourne" (or similar, depending on the full scope)

let cityDebugName = String(reflecting: city)
// cityDebugName contains "App.City.Melbourne"

これらの各シナリオで印刷されるものをカスタマイズできることに注意してください。

extension City: CustomStringConvertible {
    var description: String {
        return "City \(rawValue)"
    }
}

print(city)
// prints "City 1"

extension City: CustomDebugStringConvertible {
    var debugDescription: String {
        return "City (rawValue: \(rawValue))"
    }
}

debugPrint(city)
// prints "City (rawValue: 1)"

(この「デフォルト」値を呼び出す方法、たとえばswitch文に頼らずに「The city is Melbourne」を印刷する方法が見つかりませんでした。実装での\(self)の使用description/debugDescriptionを使用すると、無限再帰が発生します。)


上記のStringinit(_:)およびinit(reflecting:)イニシャライザーは、リフレクションされた型が準拠するものに応じて、印刷される内容を正確に説明します。

extension String {
    /// Initialize `self` with the textual representation of `instance`.
    ///
    /// * If `T` conforms to `Streamable`, the result is obtained by
    ///   calling `instance.writeTo(s)` on an empty string s.
    /// * Otherwise, if `T` conforms to `CustomStringConvertible`, the
    ///   result is `instance`'s `description`
    /// * Otherwise, if `T` conforms to `CustomDebugStringConvertible`,
    ///   the result is `instance`'s `debugDescription`
    /// * Otherwise, an unspecified result is supplied automatically by
    ///   the Swift standard library.
    ///
    /// - SeeAlso: `String.init<T>(reflecting: T)`
    public init<T>(_ instance: T)

    /// Initialize `self` with a detailed textual representation of
    /// `subject`, suitable for debugging.
    ///
    /// * If `T` conforms to `CustomDebugStringConvertible`, the result
    ///   is `subject`'s `debugDescription`.
    ///
    /// * Otherwise, if `T` conforms to `CustomStringConvertible`, the result
    ///   is `subject`'s `description`.
    ///
    /// * Otherwise, if `T` conforms to `Streamable`, the result is
    ///   obtained by calling `subject.writeTo(s)` on an empty string s.
    ///
    /// * Otherwise, an unspecified result is supplied automatically by
    ///   the Swift standard library.
    ///
    /// - SeeAlso: `String.init<T>(T)`
    public init<T>(reflecting subject: T)
}


この変更に関する情報については、 リリースノート を参照してください。

116
Stuart

現時点では列挙型のケースについては内省していません。それぞれ手動で宣言する必要があります。

enum City : String, Printable {
  case Melbourne = "Melbourne"
  case Chelyabinsk = "Chelyabinsk"
  case Bursa = "Bursa"

  var description : String {
    get {
        return self.rawValue
    }
  }
}

Printableプロトコルは、現在Playgroundsでは機能しません。プレイグラウンドで文字列を表示したい場合は、手動でtoRaw()を呼び出す必要があります

Raw型をIntにする必要がある場合は、自分で切り替えを行う必要があります。

enum City : Int, Printable {
  case Melbourne = 1, Chelyabinsk, Bursa

  var description : String {
    get {
      switch(self) {
        case Melbourne:
          return "Melbourne"
        case Chelyabinsk:
          return "Chelyabinsk"
        case Bursa:
          return "Bursa"
      }
    }
  }
}
70
drewag

Swift-3(Xcode 8.1でテスト済み)では、次のメソッドを列挙に追加できます。

/**
 * The name of the enumeration (as written in case).
 */
var name: String {
    get { return String(describing: self) }
}

/**
 * The full name of the enumeration
 * (the name of the enum plus dot plus the name as written in case).
 */
var description: String {
    get { return String(reflecting: self) }
}

その後、enumインスタンスの通常のメソッド呼び出しとして使用できます。以前のSwiftバージョンでも動作する可能性がありますが、テストしていません。

あなたの例では:

enum City: Int {
    case Melbourne = 1, Chelyabinsk, Bursa
    var name: String {
        get { return String(describing: self) }
    }
    var description: String {
        get { return String(reflecting: self) }
    }
}
let city = City.Melbourne

print(city.name)
// prints "Melbourne"

print(city.description)
// prints "City.Melbourne"

すべての列挙型にこの機能を提供する場合は、拡張機能にすることができます。

/**
 * Extend all enums with a simple method to derive their names.
 */
extension RawRepresentable where RawValue: Any {
  /**
   * The name of the enumeration (as written in case).
   */
  var name: String {
    get { return String(describing: self) }
  }

  /**
   * The full name of the enumeration
   * (the name of the enum plus dot plus the name as written in case).
   */
  var description: String {
    get { return String(reflecting: self) }
  }
}

これはSwift列挙型でのみ機能します。

31
Matthias Voss

現在、Objective-Cのenumsの唯一の方法は、CustomStringConvertibleで列挙型を拡張して、次のようなものにすることです。

extension UIDeviceBatteryState: CustomStringConvertible {
    public var description: String {
        switch self {
        case .Unknown:
            return "Unknown"
        case .Unplugged:
            return "Unplugged"
        case .Charging:
            return "Charging"
        case .Full:
            return "Full"
        }
    }
}

そして、enumStringとしてキャストします。

String(UIDevice.currentDevice().batteryState)
15

これはとても残念です。

これらの名前が必要な場合(コンパイラーは正確なスペルを完全に知っているが、アクセスを許可しない-ありがとうSwiftチーム!!-)が、Stringを必要としないか、作成できない場合列挙型のベースである、冗長で扱いにくい選択肢は次のとおりです。

enum ViewType : Int, Printable {

    case    Title
    case    Buttons
    case    View

    static let all = [Title, Buttons, View]
    static let strings = ["Title", "Buttons", "View"]

    func string() -> String {
        return ViewType.strings[self.rawValue]
    }

    var description:String {
        get {
            return string()
        }
    }
}

上記を次のように使用できます。

let elementType = ViewType.Title
let column = Column.Collections
let row = 0

println("fetching element \(elementType), column: \(column.string()), row: \(row)")

そして、期待される結果が得られます(同様の列のコードは表示されません)

fetching element Title, column: Collections, row: 0

上記では、descriptionプロパティがstringメソッドを参照するようにしましたが、これは好みの問題です。また、いわゆるstatic変数は、その型を囲む型の名前でスコープ修飾される必要があることに注意してください。コンパイラは記憶が強すぎて、単独でコンテキストをリコールできないためです...

Swiftチームは実際に指揮する必要があります。彼らはenumerateを使用できない列挙型を作成し、enumerateを使用できる列挙型は "Sequences"ですが、enumではありません!

5
verec

Swift 2.2の列挙型のString(…)(CustomStringConvertible)のサポートに加えて、いくつかの壊れたリフレクションのサポートもあります。値が関連付けられている列挙型ケースの場合、リフレクションを使用して列挙型ケースのラベルを取得できます。

enum City {
    case Melbourne(String)
    case Chelyabinsk
    case Bursa

    var label:String? {
        let mirror = Mirror(reflecting: self)
        return mirror.children.first?.label
    }
}

print(City.Melbourne("Foobar").label) // prints out "Melbourne"

ただし、壊れているということは、「単純な」列挙型の場合、上記のリフレクションベースのlabel計算プロパティはnil(boo-hoo)を返すだけであることを意味していました。

print(City.Chelyabinsk.label) // prints out nil

明らかに、Swift 3の後、反射の状況は改善されるはずです。現時点での解決策は、他の回答の1つで提案されているように、String(…)です。

print(String(City.Chelyabinsk)) // prints out Cheylabinsk
5
mz2

Swiftの場合:

extension UIDeviceBatteryState: CustomStringConvertible {
    public var description: String {
        switch self {
        case .unknown:
            return "unknown"
        case .unplugged:
            return "unplugged"
        case .charging:
            return "charging"
        case .full:
            return "full"
        }
    }
}

変数「batteryState」の場合:

self.batteryState.description

3
xevser

Swiftには、 暗黙的に割り当てられた生の値 と呼ばれるものがあります。基本的に、各ケースに未加工の値を指定せず、enumがString型である場合、ケースの未加工の値自体が文字列形式であると推定されます。試してみてください。

enum City: String {
  case Melbourne, Chelyabinsk, Bursa
}

let city = City.Melbourne.rawValue

// city is "Melbourne"
2
NSCoder

シンプルだが機能する...

enum ViewType : Int {
    case    Title
    case    Buttons
    case    View
}

func printEnumValue(enum: ViewType) {

    switch enum {
    case .Title: println("ViewType.Title")
    case .Buttons: println("ViewType.Buttons")
    case .View: println("ViewType.View")
    }
}
2
Jimbo Jones

String(describing:)イニシャライザを使用して、String以外のrawValuesを持つ列挙型であってもケースラベル名を返すことができます。

enum Numbers: Int {
    case one = 1
    case two = 2
}

let one = String(describing: Numbers.one) // "one"
let two = String(describing: Numbers.two) // "two"

Enumが@objc修飾子を使用する場合、これはnot動作することに注意してください。

https://forums.Swift.org/t/why-is-an-enum-returning-enumname-rather-than-caselabel-for-string-describing/27327

Objective-Cタイプ用に生成されたSwiftインターフェイスには、@objc修飾子が含まれない場合があります。それでも、それらのEnumはObjective-Cで定義されているため、上記のようには機能しません。

1
pkamb