Wie kann man in Swift eine Aufzählung vom Rohwert erhalten?

74

Ich versuche, den Aufzählungstyp aus dem Rohwert zu ermitteln:

enum TestEnum: String {
    case Name
    case Gender
    case Birth

    var rawValue: String {
        switch self {
        case .Name: return "Name"
        case .Gender: return "Gender"
        case .Birth: return "Birth Day"
        }
    }
}

let name = TestEnum(rawValue: "Name")       //Name
let gender = TestEnum(rawValue: "Gender")   //Gender

Aber es scheint, dass rawValuedies für Zeichenfolgen mit Leerzeichen nicht funktioniert:

let birth = TestEnum(rawValue: "Birth Day") //nil

Irgendwelche Vorschläge, wie man es bekommt?

Löwe
quelle
Bitte werfen Sie einen Blick darauf: http://stackoverflow.com/a/38390421/3024579
Alok

Antworten:

134

Zu kompliziert, weisen Sie die Rohwerte einfach direkt den Fällen zu

enum TestEnum: String {
  case Name = "Name"
  case Gender = "Gender"
  case Birth = "Birth Day"
}

let name = TestEnum(rawValue: "Name")!       //Name
let gender = TestEnum(rawValue: "Gender")!   //Gender
let birth = TestEnum(rawValue: "Birth Day")! //Birth

Wenn der Fallname mit dem Rohwert übereinstimmt, können Sie ihn sogar weglassen

enum TestEnum: String {
  case Name, Gender, Birth = "Birth Day"
}

In Swift 3+ sind alle Enum-Fälle lowercased

vadian
quelle
2
Abgesehen davon, dass die Variablen nameusw. jetzt Optionals sind, was wahrscheinlich nicht das ist, was das OP will.
Matt
2
Es gibt keine andere Möglichkeit, als eine Option zurückzugewinnen (es sei denn, Sie möchten einen Absturz, wenn eine Zeichenfolge übergeben wird, die keinem Aufzählungsfall entspricht).
Marcus Rossel
@matt - richtig, aber da Sie die Fallnamen zur Kompilierungszeit kennen, können Sie die Optionen sicher auspacken. Ich habe die Antwort bearbeitet.
Vadian
Ausgezeichnet. Ich denke, das OP wird das nützlicher finden!
Matt
4
Das erzwungene Entpacken einer aus RawValue erstellten Aufzählung kann zu Laufzeitausnahmen führen. Es wäre besser, die Konstruktion "if let" zu verwenden, um den Wert zu entpacken. Siehe auch: Apple Enum Raw Value Dokumentation
Hugo
14

Vollständiges Arbeitsbeispiel:

enum TestEnum: String {
    case name = "A Name"
    case otherName
    case test = "Test"
}

let first: TestEnum? = TestEnum(rawValue: "A Name")
let second: TestEnum? = TestEnum(rawValue: "OtherName")
let third: TestEnum? = TestEnum(rawValue: "Test")

print("\(first), \(second), \(third)")

All dies funktioniert, aber bei der Initialisierung mit einem Rohwert ist dies optional. Wenn dies ein Problem ist, können Sie einen Initialisierer oder Konstruktor für die Aufzählung erstellen, um dies zu versuchen, einen noneFall hinzufügen und ihn zurückgeben, wenn die Aufzählung nicht erstellt werden konnte. Etwas wie das:

static func create(rawValue:String) -> TestEnum {
        if let testVal = TestEnum(rawValue: rawValue) {
            return testVal
        }
        else{
            return .none
        }
    }
NoLongerContributingToSE
quelle
init(_ str: String) { self = TestEnum(rawValue: str) ?? .none }als zusätzliche Init macht das gleiche
bbjay
Das ist eine andere Option. Persönlich bevorzuge ich es, wenn möglich, Inits mit denselben typisierten Parametern zu vermeiden.
NoLongerContributingToSE
5

Mit Swift 4.2 und CaseIterable ist es gar nicht so schwer!

Hier ist ein Beispiel für die Implementierung.

import UIKit

private enum DataType: String, CaseIterable {
    case someDataOne = "an_awesome_string_one"
    case someDataTwo = "an_awesome_string_two"
    case someDataThree = "an_awesome_string_three"
    case someDataFour = "an_awesome_string_four"

    func localizedString() -> String {
        // Internal operation
        // I have a String extension which returns its localized version
        return self.rawValue.localized
    }

    static func fromLocalizedString(localizedString: String) -> DataType? {
        for type in DataType.allCases {
            if type.localizedString() == localizedString {
                return type
            }
        }
        return nil
    }

}

// USAGE EXAMPLE
override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    if let dataType = DataType.fromLocalizedString(localizedString: self.title) {
        loadUserData(type: dataType)
    }
}

Sie können es leicht ändern, um den Datentyp basierend auf dem rawValue zurückzugeben. Ich hoffe, es hilft!

BelfDev
quelle
Ich glaube, dass etwas mit dem Design nicht stimmt, wenn ein Enum-Fall aus einer lokalisierten Zeichenfolge wiederhergestellt werden muss.
Leo
@Leo, es ist völlig in Ordnung zu diskutieren, ob das Abrufen von Aufzählungszeichen aus einer lokalisierten Zeichenfolge ideal ist oder nicht. Tatsächlich stimme ich Ihnen persönlich zu, dass dies nicht der Fall ist - aber manchmal arbeiten wir in großen Projekten, in denen wir nicht einfach alles ändern können, was wir wollen. Das heißt, ich denke, Sie werden mir zustimmen, wenn ich sage, dass diese Art der Diskussion außerhalb des Rahmens liegt ... Der springende Punkt ist, dass Sie Enum-Fälle von einem bestimmten zugehörigen Typ abrufen können. Es beantwortet Ihre erste Frage aus dem Jahr 2016. Prost!
BelfDev
4

Sie können eine Aufzählung wie folgt definieren :

enum TestEnum: String {
    case Name, Gender, Birth
}

ODER

enum TestEnum: String {
    case Name
    case Gender
    case Birth
}

Sie können eine init- Methode bereitstellen , die standardmäßig einen der Elementwerte verwendet.

enum TestEnum: String {
    case Name, Gender, Birth

    init() {
        self = .Gender
    }
}

Im obigen Beispiel hat TestEnum.Name den impliziten Rohwert "Name" usw.

Sie greifen auf den Rohwert eines Aufzählungsfalls mit seiner Eigenschaft rawValue zu:

let testEnum = TestEnum.Name.rawValue
// testEnum is "Name"
let testEnum1 = TestEnum() 
// testEnum1 is "Gender"
keshav vishwkarma
quelle
3

Zeigen Sie den Rohwert mit Enum an

import UIKit

enum car: String {
    case bmw =  "BMW"
    case jaquar = "JAQUAR"
    case rd = "RD"
    case benz = "BENZ"

}


class ViewController: UIViewController {

    @IBOutlet weak var label: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        label.text = car.bmw.rawValue

    }


}
CSE 1994
quelle
1

Hier ist ein Beispiel für besser verwendbaren Code in Swift 4.1

import UIKit

enum FormData {
  case userName
  case password

  static let array = [userName, password]

  var placeHolder: String {
    switch self {
    case .userName:
      return AppString.name.localized // will return "Name" string
    case .password:
      return AppString.password.localized // will return "Password" string
    }
  }
}

enum AppString: String {
  case name = "Name"
  case password = "Password"

  var localized: String {
    return NSLocalizedString(self.rawValue, comment: "")
  }
}
Gurjinder Singh
quelle
1

Ich denke, dies ist eine schnelle und saubere Lösung für Swift 4.2 (Sie können zum Spielplatz gehen)

import UIKit

public enum SomeEnum: String, CaseIterable {
    case sun,moon,venus,pluto
}

let str = "venus"
let newEnum = SomeEnum.allCases.filter{$0.rawValue == str}.first
// newEnum is optional
if let result = newEnum {
    print(result.rawValue)
}
Zvika Ashkenazi
quelle