Swift'de numaralandırma değerinin adı nasıl alınır?


167

Ham Integerdeğerleri olan bir numaralandırma varsa :

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

let city = City.Melbourne

Bir citydeğeri bir dizeye nasıl dönüştürebilirim Melbourne? Bu tür bir tür adı tanıtımı dilde mevcut mu?

Gibi bir şey (bu kod çalışmaz):

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

Yanıtlar:


139

Xcode 7 beta 5 (Swift sürüm 2) itibariyle artık kullanarak varsayılan olarak tip isimleri ve numaralandırma davaları yazdırabilir print(_:), ya da dönüştürmek Stringkullanarak String'ın init(_:)başlatıcı veya dize enterpolasyon sözdizimi. Yani örneğiniz için:

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"

Dolayısıyla, bir dizgi değişmezini döndürmek için her durumu açan bir kolaylık işlevini tanımlamaya ve sürdürmeye artık gerek yoktur. Buna ek olarak, ham değer türü belirtilmemiş olsa bile, herhangi bir numaralandırma için otomatik olarak çalışır.

debugPrint(_:)& String(reflecting:)tam nitelikli bir ad için kullanılabilir:

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

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

Bu senaryoların her birinde yazdırılanları özelleştirebileceğinizi unutmayın:

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

(Ben, örneğin, bir anahtar açıklamaya geri başvurmadan "şehir Melbourne olduğunu" yazdırmak için. Kullanmak, bu "varsayılan" değer haline çağrı için bir yol bulamadı \(self)uygulanmasında description/ debugDescriptionsonsuz özyinelemeye neden olur.)


Yukarıdaki yorumlar Stringbireyin init(_:)ve init(reflecting:)başlatıcıları ne yansıyan tip uygun olup bağlı olarak yazdırılır tam olarak ne açıklar:

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


Bu değişiklik hakkında bilgi için sürüm notlarına bakın .


8
Ayrıca dize değerini kullanmadan print(enum)istiyorsanız kullanabilirsinizString(enum)
Kametrixom

44
Önemli yakalama, bu sadece Swift numaralandırmalar için çalışır. OS X'te ciltleme desteğine izin vermek için @objc olarak etiketlerseniz, bu çalışmaz.
Claus Jørgensen

11
Hızlı Swift'e özel cevap; ancak bunu CLAuthorizationStatus, locationManager didChangeAuthorizationStatustemsilci geri aramanızdaki (Objective C) enum değerini yazdırmak gibi hızlı olmayan bir numaralandırmada yapmanız gerekirse, bir protokol uzantısı tanımlamanız gerekir. Örneğin: extension CLAuthorizationStatus: CustomStringConvertable { public var description: String { switch self { case .AuthorizedAlways: return "AuthorizedAlways" <etc> } } }- bunu yaptıktan sonra, beklediğiniz gibi çalışmalıdır: print ("Yetkilendirme durumu: (\ durum))".
Jeffro

3
"Xcode 7 beta 5 itibariyle" anlamsız. Bunlardan herhangi birini tanımlayan Xcode değil, Swift derleyicisi ve Swift Runtime Libaries. Xcode 9.3'ü kullanabilirim ancak Kodum hala Swift 3 olabilir ve daha sonra Swift 4 özelliklerini kullanamayacağım. Xcode 9.3 kullanıldığında, Xcode
9.3'ün

8
Başlatıcı 'init (_ :)' var Şehir xcode 10.2, Swift 5 üzerinde 'LosslessStringConvertible' uygun olmasını gerektirir Şimdi nasıl yapacağız?
rockgecko

73

Şu an enum vakalarında içgözlem yoktur. Her birini manuel olarak bildirmeniz gerekir:

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

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

Int için ham türüne ihtiyacınız varsa, kendiniz bir anahtar yapmanız gerekir:

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

2
Noob sorusu, ama neden sadece self.value döndürmek yerine get {return self.rawValue} ifadesini koydu? İkincisini denedim ve gayet iyi çalışıyor.
Chuck Krutsinger

get { ... }Bir ayarlayıcı tanımlamazsanız kısmi kısalık kısmını da atlayabilirsiniz .
iosdude

1
Harika cevap için teşekkürler. Xcode 7.3'te şunu alıyorum: "Yazdırılabilir CustomStringConvertible olarak yeniden adlandırıldı". Çözüm kolaydır - yukarıdaki ilk kod örneğinde, ilk satırı olarak değiştirin enum City : String, CustomStringConvertible {. CSC protokolünün bir parçası olarak, mülkü herkese açık olacak şekilde değiştirmeniz gerekir , örneğin:public var description : String {
Jeffro

44

Swift-3'te (Xcode 8.1 ile test edilmiştir) numaralandırmanıza aşağıdaki yöntemleri ekleyebilirsiniz:

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

Daha sonra numaralandırma örneğinizde normal bir yöntem çağrısı olarak kullanabilirsiniz. Önceki Swift sürümlerinde de işe yarayabilir, ancak test etmedim.

Örneğinizde:

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"

Bu işlevselliği tüm numaralandırmalarınıza sağlamak istiyorsanız, bunu bir uzantı yapabilirsiniz:

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

Bu sadece Swift numaralandırmalar için geçerlidir.


18

Objective-Cs enumiçin şu anda, örneğin, enum CustomStringConvertiblegibi bir şey ile sona erdirmek için gibi görünüyor:

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

Ve sonra enumas döküm String:

String(UIDevice.currentDevice().batteryState)

12

String(describing:)Başlatıcı bile olmayan dize rawValues ile çeteleler için durum etiket adını döndürmek için kullanılabilir:

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

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

Eğer numaralandırma enum kullanıyorsa, bunun çalışmadığını unutmayın@objc değiştiriciyi :

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

Objective-C türleri için oluşturulan Swift arabirimleri bazen @objcdeğiştiriciyi içermez . Bununla birlikte, bu Numaralamalar Objective-C'de tanımlanmıştır ve bu nedenle yukarıdaki gibi çalışmaz.


7

Swift 2.2'de dize (…) (CustomStringConvertible) desteğinin üstünde, onlar için de biraz kırık yansıma desteği var. İlişkili değerlere sahip numaralandırma durumları için yansıma kullanarak numaralandırma durumunun etiketini almak mümkündür:

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"

Ancak, kırılarak, "basit" numaralar için, yukarıdaki yansıma tabanlı labelhesaplanmış özellik sadece nil(boo-hoo) döner demekti .

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

Yansıması olan durum Swift 3'ten sonra iyileşiyor gibi görünüyor. Şimdilik çözüm String(…), diğer cevaplardan birinde önerildiği gibi:

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

2
Bu, isteğe bağlı hale getirmeye gerek kalmadan Swift 3.1 üzerinde çalışıyor gibi görünüyor:var label:String { let mirror = Mirror(reflecting: self); if let label = mirror.children.first?.label { return label } else { return String(describing:self) } }
David James

5

Bu çok hayal kırıklığı yaratıyor.

Bu adlara ihtiyacınız olduğunda (derleyici tam yazımını mükemmel bir şekilde bilir, ancak erişime izin vermeyi reddeder - teşekkür ederim Swift ekibi !! -) ancak String'i sıralamanızın temeli yapmak istemez veya yapamazsınız, ayrıntılı, hantal alternatif aşağıdaki gibidir:

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

Yukarıdakileri aşağıdaki gibi kullanabilirsiniz:

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

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

Ve beklenen sonucu elde edersiniz (Sütun kodu benzer, ancak gösterilmez)

fetching element Title, column: Collections, row: 0

Yukarıda, descriptionmülkün stringyönteme geri dönmesini sağladım, ancak bu bir zevk meselesi. Ayrıca static, derleyici çok amnezik olduğundan ve bağlamı tek başına hatırlayamadığından, sözde değişkenlerin çevreleyen türlerinin adıyla kapsam nitelikli olması gerektiğini unutmayın ...

Swift ekibine gerçekten komut verilmesi gerekiyor. Yapamayacağınız enumerateve kullanabileceğiniz enum yarattılar enumerate"Diziler" ama değil enum!


Bu sadece dönüşte String (yansıtan: self) yapmaktan ziyade uzun soluklu görünüyor.
Boon

4

Ben bu soruya çarptım ve belirtilen sihir oluşturmak için basit bir yol paylaşmak istedim

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

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

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

3

Swift şimdi Örtük Olarak Atanan Ham Değer olarak bilinen şeye sahiptir . Temel olarak, her bir duruma ham değerler vermezseniz ve enum String türündeyse, davanın raw değerinin kendisinin dize biçiminde olduğu sonucuna varır. Hadi bir dene.

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

let city = City.Melbourne.rawValue

// city is "Melbourne"

3

Swift için:

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

}

değişkeniniz "batteryState" ise şu numarayı arayın:

self.batteryState.description

1

Basit ama çalışıyor ...

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

0

Swift Enums'taki içgözlem kısmen işe yarıyor gibi görünüyor.

@ Drewag'ın yanıtını gördüm ve rawValues ​​içermeyen bir Enum'un Xcode 11.5 ile Swift 5.X'te içgözlem yapabileceğini buldum. Bu kod çalışır.

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)

"\(self)"For öğesini "string"ikinci olarak değiştirin ve Enumşu çıktıyı alacaksınız: network 404 string

NOT: Enum LosslessStringConvertible` protokolü String(self)yerine kullanmak ve diğer başlatıcıları eklemek, böylece dize enterpolasyonu iyi bir çözüm gibi görünüyor."\(self)" in the first will require the Enum to conform to the

var description: StringNumaralandırmaya a eklemek için, daha önce işaret edildiği gibi tüm numaralandırma durumlarını değiştirecek bir Switch deyimi kullanmanız gerekecektir.

var description: String {
    switch self {
    case .success: return "Success"
    case .created: return "Created"
    case .accepted: return "Accepted"
    }
}
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.