簡體   English   中英

如何在 Swift 中獲取枚舉值的名稱?

[英]How to get the name of enumeration value in 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

從 Xcode 7 beta 5(Swift 版本 2)開始,您現在可以默認使用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"

所以不再需要定義和維護一個方便的函數來打開每個 case 以返回一個字符串文字。 此外,即使未指定原始值類型,這也會自動適用於任何枚舉。

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

(我還沒有找到調用這個“默認”值的方法,例如,打印“The city is Melbourne”而不求助於 switch 語句。在description / debugDescription的實現中使用\\(self)會導致無限遞歸。)


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


有關此更改的信息,請參閱發行說明

目前沒有對枚舉案例的內省。 您必須手動聲明它們:

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

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

如果您需要原始類型為 Int,則必須自己進行切換:

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

  var description: String {
    get {
      switch self {
        case .Melbourne:
          return "Melbourne"
        case .Chelyabinsk:
          return "Chelyabinsk"
        case .Bursa:
          return "Bursa"
      }
    }
  }
}

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

然后,您可以將其用作枚舉實例上的普通方法調用。 它可能也適用於以前的 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 枚舉。

對於 Objective-C enum s,目前似乎唯一的方法是,例如,使用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)

String(describing:) describing String(describing:)初始值設定項可用於返回 case 標簽名稱,即使對於具有非 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"

注意如果枚舉使用,這並不工作@objc修改:

為 Objective-C 類型生成的 Swift 接口有時不包含@objc修飾符。 然而,這些枚舉是在 Objective-C 中定義的,因此不像上面那樣工作。

除了 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 之后,反射的情況應該會變得更好。 現在的解決方案是String(…) ,正如其他答案之一所建議的:

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

我碰到了這個問題,想分享一個簡單的方法來創建提到的magicFunction

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

    func magicFunction() -> String {
        return "\(self)"
    }
}

let city = City.Melbourne
city.magicFunction() //prints Melbourne

這太令人失望了。

如果您需要這些名稱(編譯器完全知道其確切拼寫,但拒絕訪問——謝謝 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的是“序列”而不是enum

Swift 現在具有所謂的隱式分配原始值 基本上,如果您不為每個 case 提供原始值並且枚舉的類型為 String,則它會推斷 case 的原始值本身就是字符串格式。 去試試吧。

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

let city = City.Melbourne.rawValue

// city is "Melbourne"

對於斯威夫特:

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

簡單但有效...

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

Swift Enums 中的內省似乎部分起作用。

我看到@drewag 的回復,發現沒有 rawValues 的 Enum 確實可以在 Swift 5.X 和 Xcode 11.5 中進行自省。 此代碼有效。

public enum Domain: String {
    case network
    case data
    case service
    case sync
    var description: String {
        return "\(self)"     // THIS INTROSPECTION WORKS
    }
}
enum ErrorCode: Int, CustomStringConvertible {
    case success = 200
    case created = 201
    case accepted = 202
    case badRequest = 400
    case unauthorized = 401
    case forbidden = 403
    case notFound = 404
    var code: Int {
        return self.rawValue
    }
    var description: String {
        return "\(self)"      //THIS DOES NOT WORK - EXEC_BAD_ACCESS
    }
}
let errorCode = ErrorCode.notFound
let domain = Domain.network
print(domain.description, errorCode.code, errorCode.description)

在第二個Enum中將"\\(self)"替換為"string" ,您將得到以下打印輸出:network 404 string

注意: "\\(self)" in the first Enum 中使用String(self)而不是"\\(self)" in the first will require the Enum to conform to the LosslessStringConvertible` 協議,並添加其他初始值設定項,因此字符串插值似乎是一個很好的解決方法。

要將var description: String添加到枚舉中,您將必須使用 Switch 語句將所有枚舉情況與之前指出的一樣

var description: String {
    switch self {
    case .success: return "Success"
    case .created: return "Created"
    case .accepted: return "Accepted"
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM