How can achieve Enum to have a arguments on a case - swift

I have an enum which has a String raw value. I want one of the cases get a string as input and return a string which that input. How can I achieve this?
public enum PredictTypes: String {
case favtasks = "isFav == YES"
case importtanttasks = "isImportant == YES"
case alltasks = ""
case customList(listName: String) = "listName == \(listName)"
}
As I searched I found some posts but can't understand for my case:
Can associated values and raw values coexist in Swift enumeration?

I would rewrite your enum like this:
public enum PredictTypes {
case favtasks
case importanttasks
case alltasks
case customList(listName: String)
var rawValue: String {
switch self {
case .favtasks: return "isFav == YES"
case .importanttasks: return "isImportant == YES"
case .alltasks: return ""
case .customList(let listName): return "listName == \(listName)"
}
}
}

Related

How to create Enum for hardcoded string in swift?

I have some hardcoded string, based on that i have created switch case. But instead of string in switch case i am trying to create Enum for same. but i am not sure how to do that. I dont want to use default case.
Do i need to access with raw value or any other better way to do ?
enum screens: String {
case faq = "faq", contactus = "contactus", termncondi = "termncondi", dashoboard = "dashoboard"
}
func deepLink(text: String) -> String {
switch text {
case "faq":
return (FAQ.localized())
case "contactus":
return (Contactus.localized())
case "termncondi":
return (Term.localized())
case "dashoboard":
return (Dashboard.localized())
default:
return ""
}
}
You can simply define the enum and override the rawValue property like so:
enum Link {
case faq
case contact
...
var rawValue: String {
switch self {
case .faq:
return FAQ.localized()
case .contact:
return Contact.localized()
default:
return "Unknown case"
}
}
}
And get its rawValue.
let faqLink = Link.faq.rawValue
You can also perform a switch on an enum instance just like you do with a string.
In order to get hardcoded values do something like:
public extension String {
static func getScreens(name: DeepLink) -> String {
return name.rawValue
}
public enum DeepLink: String {
case faq = "faq"
case contactus = "contactus"
// and so on
}
}

Swift ENUM how to convert "rawValue" back to Enum case?

I have an enum:
enum switch : String {
case on = "powerOn"
case off = "powerOff"
var japanswitch : String {
case .on : return "onpu"
case .off : return "offu"
}
}
In my code my function passed down "powerOn" as pure string parameter. The problem is some point of my function require to translate "powerOn" to japanswitch.
But problem is "powerOn" right now is nothing more than a mere String which has no relationship to japanswitch at all.
How do I translate "powerOn" to japanswitch? The desired result should be "onpu".
First you need to fix your code so that it compiles:
enum Switch : String {
case on = "powerOn"
case off = "powerOff"
var japanswitch : String {
switch self {
case .on : return "onpu"
case .off : return "offu"
}
}
}
Then you can achieve what you are after using:
let japanese = Switch(rawValue:"powerOn")?.japanswitch
Note that japanese will be an optional; you need to decide how you will handle an invalid raw value.
Keyword 'switch' cannot be used as an identifier so you need to add some another keyword like below:
enum SwitchType : String {
case on = "powerOn"
case off = "powerOff"
var japanswitch : String {
switch self {
case .on : return "onpu"
case .off : return "offu"
}
}
}
Try this one
enum ABC : String {
case on = "powerOn"
case off = "powerOff"
var japanswitch : String {
return self == .on ? "onpu" : "offu"
}
}
var a = ABC(rawValue: "powerOn")
print(a!.japanswitch)
Your question is not very clear, would be helpful if you show us the code you're trying to run using this enum, but I think you can do something like this:
import Foundation
enum SwitchType: String {
case on = "powerOn"
case off = "powerOff"
var japaneseRepresentation : String {
switch (self){
case Toggle.on : return "onpu"
case Toggle.off : return "offu"
default: return Toggle.on.japaneseRepresentation
}
}
init(japanString japanString: String) {
switch(japanString) {
case "onpu": self = Toggle.on
case "offu": self = Toggle.off
default: self = Toggle.on
}
}
}
let a = Toggle(rawValue: "powerOn")
print(a)
let b = Toggle(japanString: "onpu")
print(b)
print(a == b)
The benefit of doing this is that you can have a custom initializer to work with the same enum but initializing it from a Japaneses string.
enum Switch : String {
case on = "powerOn"
case off = "powerOff"
var japanswitch : String {
switch self {
case .on:
return "onpu"
case .off:
return "offu"
}
}}
You cannot use a case without a switch statement. So can try the above snippet. after defining enum as above, as per official Apple doc you can convert a string value to enum as follows.
If you define an enumeration with a raw-value type, the enumeration
automatically receives an initializer that takes a value of the raw
value’s type (as a parameter called rawValue) and returns either an
enumeration case or nil. You can use this initializer to try to create
a new instance of the enumeration.
This example identifies japanswitch from Switch's raw value of "powerOn":
let japanswitchValue = Switch(rawValue: "powerOn")?.japanswitch
Completely different solution, if you are only using the enum for translation then you can replace it with a dictionary
let japaneseTranslation = ["powerOn": "onpu", "powerOff": "offu"]
...
let offJapanese = japaneseTranslation["powerOff"]

Using `if-case` format in boolean assignment in Swift?

If I have the following enum defined:
enum CardRank {
case number(Int)
case jack
case queen
case king
case ace
}
I know I can use an if-let to check if it's a number:
let cardRank = CardRank.number(5)
if case .number = cardRank {
// is a number
} else {
// something else
}
Instead of using an if statement, though, I want to assign the boolean result of "is this a number" to a variable.
E.g. something like this:
let isNumber = (case .number = cardRank)
However, this gives me the compiler error:
error: expected expression in list of expressions
let isNumber = (case .number = cardRank)
^
Is there a similar 1-line syntax to get this kind of assignment to work?
The closest I got was this, but it's pretty messy:
let isNumber: Bool = { if case .number = cardRank { return true } else { return false } }()
I know I can implement the Equatable protocol on my enum, and then do the following:
let isAce = cardRank == .ace
But I'm looking for a solution that doesn't require needing to conform to the Equatable protocol.
Add it as a property on the enum:
extension CardRank {
var isNumber: Bool {
switch self {
case .number: return true
default: return false
}
}
}
let isNumber = cardRank.isNumber

In Swift, is it possible to convert a string to an enum?

If I have an enum with the cases a,b,c,d is it possible for me to cast the string "a" as the enum?
Sure. Enums can have a raw value. To quote the docs:
Raw values can be strings, characters, or any of the integer or
floating-point number types
— Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks. https://itun.es/us/jEUH0.l,
So you can use code like this:
enum StringEnum: String
{
case one = "value one"
case two = "value two"
case three = "value three"
}
let anEnum = StringEnum(rawValue: "value one")!
print("anEnum = \"\(anEnum.rawValue)\"")
Note: You don't need to write = "one" etc. after each case. The default string values are the same as the case names so calling .rawValue will just return a string
EDIT
If you need the string value to contain things like spaces that are not valid as part of a case value then you need to explicitly set the string. So,
enum StringEnum: String
{
case one
case two
case three
}
let anEnum = StringEnum.one
print("anEnum = \"\(anEnum)\"")
gives
anEnum = "one"
But if you want case one to display "value one" you will need to provide the string values:
enum StringEnum: String
{
case one = "value one"
case two = "value two"
case three = "value three"
}
All you need is:
enum Foo: String {
case a, b, c, d
}
let a = Foo(rawValue: "a")
assert(a == Foo.a)
let 💩 = Foo(rawValue: "💩")
assert(💩 == nil)
In Swift 4.2, the CaseIterable protocol can be used for an enum with rawValues, but the string should match against the enum case labels:
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 }
}
}
usage:
print(MyCode.withLabel("one")) // Optional(MyCode.one)
print(MyCode(rawValue: "uno")) // Optional(MyCode.one)
In case with an enum with Int type you can do it so:
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
}
}
And use:
let string = "Two"
if let item = MenuItem.enumFromString(string) {
//in this case item = 1
//your code
}
Riffing on djruss70's answer to create highly generalized solution:
extension CaseIterable {
static func from(string: String) -> Self? {
return Self.allCases.first { string == "\($0)" }
}
func toString() -> String { "\(self)" }
}
Usage:
enum Chassis: CaseIterable {
case pieridae, oovidae
}
let chassis: Chassis = Chassis.from(string: "oovidae")!
let string: String = chassis.toString()
Note: this will unfortunately not work if the enum is declared #objc. As far as I know as of Swift 5.3 there is no way to get this to work with #objc enum's except brute force solutions (a switch statement).
If someone happens to know of a way to make this work for #objc enums, I'd be very interested in the answer.
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
}
}
Extending Duncan C's answer
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)
}
}
For Int enum and their String representation, I declare enum as follows:
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
}
}
}
Usage:
order.orderState = OrderState.waiting.rawValue
let orderState = OrderState.init(rawValue: order.orderState)
let orderStateStr = orderState?.description ?? ""
print("orderStateStr = \(orderStateStr)")
I used this:
public enum Currency: CaseIterable, Codable {
case AFN = 971 // Afghani (minor=2)
case DZD = 012 // Algerian Dinar (minor=2)
...
private static var cachedLookup: [String: Currency] = [:]
init?(string: String) {
if Self.cachedLookup.isEmpty {
Self.cachedLookup = Dictionary(uniqueKeysWithValues: Self.allCases.map { ("\($0)", $0) })
}
if let currency = Self.cachedLookup[string] {
self = currency
return
} else {
return nil
}
}
}
I found the other answers make this way more complicated then it needs to be. Here is a quick and concise example.
enum Gender: String {
case male, female, unspecified
}
Simple enum, note that I added ": String" to the enum itself to declare the type as string.
Now all you have to do is:
let example: Gender = Gender(rawValue: "male")
And thats it, 'example' is now an enum of type Gender with the value of .male
There is literally nothing else you need to do in Swift 4+.

Swift enum both a string and an int

I have a situation where I'm trying to do binary decoding of some data and the data types have both a numerical value and a string value and a name. I was thinking of using an enum such as:
enum TARGET_TRACK_TYPE : String {
case TT_INVALID = "Invalid"
case TT_TRUE_TRACK_ANGLE = "True Track Angle"
case TT_MAGNETIC = "Magnetic"
case TT_TRUE = "True"
}
However I also know that:
TT_INVALID = 0 and TT_TRUE_TRACK_ANGLE = 1, etc. Is there an easy way to encapsulate both these "things" the string and the numerical value into an enum construct or do i need to make some sort of struct/class to handle this?
I guess I'd like to do something like
let a = TARGET_TRACK_TYPE.rawValue(value: 2)
println(a)
which would print True Track Angle
Again, I know this can be done with a struct or a class but I'm specifically interested in the enum
Or for another example:
/// Emitter Category is defined in section 3.5.1.10 of the GDL90 Spec
struct EmitterCategory {
let category : Int
func getString() -> String {
switch(category) {
case 0:
return "No aircraft type information";
case 1:
return "Light";
case 2:
return "Smalle";
case 3:
return "Large";
case 4:
return "High Vortex Large";
case 5:
return "Heavy";
case 6:
return "Highly Manuverable";
case 7:
return "Rotorcraft";
case 8:
return "(Unassigned)";
case 9:
return "Glider/sailplane";
case 10:
return "Ligther than air";
case 11:
return "Parachutist/sky diver";
case 12:
return "Ultra light/hang glider/paraglider";
case 13:
return "(Unassigned)";
case 14:
return "Unmanned aerial vehicle";
case 15:
return "Space/transatmospheric vehicle";
case 16:
return "(Unassigned)";
case 17:
return "Surface vehicle - emergency vehicle";
case 18:
return "Surface vehicle - service vehicle";
case 19:
return "Point obstacle";
case 20:
return "Cluster Obstacle";
case 21:
return "Line Obstacle";
default:
return "(reserved)";
}
}
}
Is there a way to refactor this struct into an enum such that I construct the enum with an integer value but I "read" the enum as a string? I'm pretty sure the answer is no.
I think this will do it for me. Thank you self.. :)
protocol GDL90_Enum {
var description: String { get }
}
enum TARGET_ADDRESS_TYPE : Int, GDL90_Enum {
case ADSB_ICAO_ADDRESS = 0
case ADSB_SELF_ADDRESS = 1
case TISB_ICAO = 2
case TISB_TRACK_ID = 3
case SURFACE_VEHICLE = 4
case GROUND_STATION = 5
var description: String {
switch self {
case .ADSB_ICAO_ADDRESS:
return "ADS-B with ICAO address"
case .ADSB_SELF_ADDRESS:
return "ADS-B with Self-assigned address"
case .TISB_ICAO:
return "TIS-B with ICAO address"
case .TISB_TRACK_ID:
return "TIS-B with track file ID"
case .SURFACE_VEHICLE:
return "Surface Vehicle"
case .GROUND_STATION:
return "Ground Station Beacon"
default:
return "Reserved"
}
}
}
With Swift 4.2 this can be done using CaseIterable. One, relatively concise way is to do the following
enum Directions: String, CaseIterable {
case north, south, east, west
static var asArray: [Directions] {return self.allCases}
func asInt() -> Int {
return Directions.asArray.firstIndex(of: self)!
}
}
print(Directions.asArray[2])
// prints "east\n"
print(Directions.east.asInt())
// prints "2\n"
print(Directions.east.rawValue)
// prints "east\n"
You should use RawRepresentable
#objc enum AppEvent:Int, RawRepresentable {
case appLaunch
case homeScreen
public typealias RawValue = String
public var rawValue: RawValue {
switch self {
case .appLaunch : return "appLaunch"
case .homeScreen : return "homeScreen"
}
public init?(rawValue: RawValue) {
switch rawValue {
case "appLaunch" : self = .appLaunch
case "homeScreen" : self = .homeScreen
}
Have you considered using a dictionary?
let targetTrackDict: [Int: String] =
[99: "Invalid",
1: "True Track Angle",
2: "Magnetic",
5: "True"]
Note the number codes don't have to be ordered or contiguous. Being specific about the dictionary's type in its declaration prevents a lot of warnings or errors in the following snippets.
Getting the name for a code is easy:
var code = 2
if let name = targetTrackDict[code] {
print("\(name) has code \(code)")
} else {
print("\(code) is not a valid track type")
}
I haven't found a tidy way of getting the code for a name, but this does it:
let magneticCode = targetTrackDict.first(where:
{key, value in value == "Magnetic"})?.key
// returns an optional
and you would of course dress it up as a function. What you don't get automatically is an internal name for your track type, but do you need one? And the line above does it for you in a way.
Summing up #Jeef's answer and #NobodyNada's comment, here's a solution
public enum Animal: Int, CustomStringConvertible {
case Dog, Cat
public var description: String {
switch self.rawValue {
case 0: return "Dog"
case 1: return "Cat"
default: return ""
}
}
}
var animal = Animal.Dog
print(animal) // Dog