Swift'de bir dizeyi bir numaralandırmaya dönüştürmek mümkün müdür?


99

A, b, c, d durumlarını içeren bir numaram varsa, "a" dizesini sıralama olarak atmam mümkün müdür?


3
Bu 'yayınlara' değişmez dönüşümler denir.
Vatsal Manot

Yanıtlar:


144

Elbette. Numaralandırmalar ham bir değere sahip olabilir. Belgelerden alıntı yapmak için:

Ham değerler dizeler, karakterler veya tam sayı veya kayan noktalı sayı türlerinden herhangi biri olabilir

- Alıntı: Apple Inc. "The Swift Programming Language." iBooks. https://itun.es/us/jEUH0.l ,

Böylece kodu şu şekilde kullanabilirsiniz:

enum StringEnum: String 
{
  case one = "one"
  case two = "two"
  case three = "three"
}

let anEnum = StringEnum(rawValue: "one")!

print("anEnum = \"\(anEnum.rawValue)\"")

Not: Her durumdan sonra = "bir" vb. Yazmanıza gerek yoktur. Varsayılan dize değerleri vaka isimleriyle aynıdır, bu nedenle çağırma .rawValueyalnızca bir dize döndürür

DÜZENLE

Dize değerinin, bir büyük / küçük harf değerinin bir parçası olarak geçerli olmayan boşluklar gibi şeyleri içermesine ihtiyacınız varsa, dizeyi açıkça ayarlamanız gerekir. Yani,

enum StringEnum: String 
{
  case one
  case two
  case three
}

let anEnum = StringEnum.one
print("anEnum = \"\(anEnum)\"")

verir

anEnum = "bir"

Ancak case one"değer bir" i görüntülemek istiyorsanız , dize değerlerini sağlamanız gerekir:

enum StringEnum: String 
{
  case one   = "value one"
  case two   = "value two"
  case three = "value three"
}

Ham değer, gerçek anlamda dönüştürülebilir olmalıdır. Herhangi bir Hashabletürü kullanamazsınız .
Vatsal Manot

1
Tamam ... Enum ham değerleri olarak kullanılabilecek değer türlerini listeleyen Apple belgelerinden alıntı yaptım. OP'nin sorusu olan dizeler desteklenen türlerden biridir.
Duncan C

1
Hmm, hayal edin case one = "uno". Şimdi, "one"enum değerine nasıl ayrıştırılır ? (yerelleştirme için kullanıldıkları için
raw'lar

Belki yerelleştirmeye bağlı olarak ilklendirme sırasında ham String'i başlatabilirsiniz ... veya sadece her biri farklı bir yerelleştirme için farklı numaralandırmaya sahip olabilirsiniz. Her durumda bir numaralandırmaya sahip olmanın tüm amacı, temeldeki ham olanı, yani yerelleştirmeyi soyutlamaktır. İyi bir kod tasarımı parametre olarak "uno" yu hiçbir yere iletmez, ancak StringEnum.one'a güvenir
SkyWalker

5
= "one"Her vakadan sonra yazmak zorunda değilsiniz . Varsayılan dize değerleri, vaka isimleriyle aynıdır.
emlai

38

Tum ihtiyacin olan sey:

enum Foo: String {
   case a, b, c, d
}

let a = Foo(rawValue: "a")
assert(a == Foo.a)

let 💩 = Foo(rawValue: "💩")
assert(💩 == nil)

Bu, ham değeri kontrol ettiği için teknik olarak doğru cevap değildir. Verildiği gibi buradaki örnekte, ham değer belirtilmemiştir, bu nedenle dolaylı olarak vaka adıyla eşleştirilmiştir, ancak ham değere sahip bir numaralamanız varsa, bu bozulur.
Mark A. Donohoe

31

Swift 4.2'de, CaseIterable protokolü rawValues ​​ile bir enum için kullanılabilir, ancak dize enum durum etiketleriyle eşleşmelidir:

enum MyCode : String, CaseIterable {

    case one   = "uno"
    case two   = "dos"
    case three = "tres"

    static func withLabel(_ label: String) -> MyCode? {
        return self.allCases.first{ "\($0)" == label }
    }
}

kullanım:

print(MyCode.withLabel("one")) // Optional(MyCode.one)
print(MyCode(rawValue: "uno"))  // Optional(MyCode.one)

2
Bu harika bir cevap! Aslında soruyu ele alıyor.
Matt Rundle

3
Bu, OP'nin sorduğu gibi gerçekten işe yarayan tek cevaptır ve ham değerler değil vaka isimleriyle ilgilidir . İyi cevap!
Mark A. Donohoe

1
Bu işe yarasa da, yapılması çok aptalca bir şey. Lütfen işlevselliği koddaki vakaların adlarına dayandırmayın.
Sulthan

7
Başka ne yapması gerekiyor? Ya bir veritabanına bir sıralama yazıyorsa ve sonra onu geri atması gerekiyorsa?
Joe

16

Int türüne sahip bir numaralandırma durumunda bunu yapabilirsiniz:

enum MenuItem: Int {
    case One = 0, Two, Three, Four, Five //... as much as needs

    static func enumFromString(string:String) -> MenuItem? {
        var i = 0
        while let item = MenuItem(rawValue: i) {
            if String(item) == string { return item }
            i += 1
        }
        return nil
    }
}

Ve kullan:

let string = "Two"
if let item = MenuItem.enumFromString(string) {
    //in this case item = 1 
    //your code
} 

2
Dilde yerleşik olarak benzer işlevselliği kullanamamanız çılgınca. JSON'daki değerleri örneğin enum adıyla depoladığınızı ve daha sonra ayrıştırmada bunları geri dönüştürmeniz gerektiğini hayal edebiliyorum. Kullandığınız enumFromStringher bir sıralama için bir yöntem yazmak çılgınca görünüyor.
Peterdk

1
@Peterdk, lütfen mümkün olan en iyi alternatifi önerin. Igor çözümü aslında benim için çalıştı.
Hemang

@Hemang Tamam çalışıyor, tamam, ancak bunu otomatik olarak yapmak için Swift desteği daha iyi bir çözüm olacaktır. Bunu her numara için elle yapmak çılgınca. Ama evet, bu işe yarıyor.
Peterdk

@Peterdk, lütfen aynısı için ayrı bir cevap ekleyebilir misiniz? Buradaki herkese kesinlikle yardımcı olur.
Hemang

1
Swift'in bunu yerel olarak desteklememesi delilik değil. Çılgın olan şey, işlevselliğin bir türün adına bağlı olmasıdır. Değer değiştiğinde, tüm kullanımları yeniden düzenlemeniz ve yeniden adlandırmanız gerekecektir. Bunu çözmenin doğru yolu bu değil.
Sulthan

2

Duncan C'nin cevabını genişletmek

extension StringEnum: StringLiteralConvertible {

    init(stringLiteral value: String){
        self.init(rawValue: value)!
    }

    init(extendedGraphemeClusterLiteral value: String) {
        self.init(stringLiteral: value)
    }

    init(unicodeScalarLiteral value: String) {
        self.init(stringLiteral: value)
    }
}

2

Swift 4.2:

public enum PaymentPlatform: String, CaseIterable {
    case visa = "Visa card"
    case masterCard = "Master card"
    case cod = "Cod"

    var nameEnum: String {
        return Mirror(reflecting: self).children.first?.label ?? String(describing: self)
    }

    func byName(name: String) -> PaymentPlatform {
        return PaymentPlatform.allCases.first(where: {$0.nameEnum.elementsEqual(name)}) ?? .cod
    }
}

2

Int enum ve String gösterimi için enumu şu şekilde bildiriyorum:

enum OrderState: Int16, CustomStringConvertible {

    case waiting = 1
    case inKitchen = 2
    case ready = 3

    var description: String {
        switch self {
        case .waiting:
            return "Waiting"
        case .inKitchen:
            return "InKitchen"
        case .ready:
            return "Ready"
        }
    }

    static func initialize(stringValue: String)-> OrderState? {
        switch stringValue {
        case OrderState.waiting.description:
            return OrderState.waiting
        case OrderState.inKitchen.description:
            return OrderState.inKitchen
        case OrderState.ready.description:
            return OrderState.ready

        default:
            return nil
        }
    }
}

Kullanım:

order.orderState = OrderState.waiting.rawValue

let orderState = OrderState.init(rawValue: order.orderState)
let orderStateStr = orderState?.description ?? ""
print("orderStateStr = \(orderStateStr)")

1

Djruss70'in oldukça genelleştirilmiş bir çözüm oluşturma cevabına değinmek:

extension CaseIterable {
    static func from(string: String) -> Self? {
        return Self.allCases.first { string == "\($0)" }
    }
    func toString() -> String { "\(self)" }
}

Kullanım:

enum Chassis: CaseIterable {
    case pieridae, oovidae
}

let chassis: Chassis = Chassis.from(string: "oovidae")!
let string: String = chassis.toString()

Not: Bu maalesef enum @objc olarak bildirilirse işe yaramayacaktır. Swift 5.3'ten bildiğim kadarıyla bunu, kaba kuvvet çözümleri (bir anahtar ifadesi) dışında @objc enum ile çalıştırmanın bir yolu yok.

Birisi bu işi @objc enums için yapmanın bir yolunu bilirse, cevapla çok ilgilenirim.

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.