I have an enum defined in Swift as follows:
public enum Command:String {
case first = "FirstCommand"
case second = "SecondCommand"
...
...
case last = "lastCommand"
}
Now I receive a command dictionary from server and I extract the command string from it. The command string would typically be one of the raw values in Command enum or sometimes it could be a command outside the enum(example, new commands are introduced in future versions of client/server but client is still old). In this scenario, what is the way to use switch statement in Swift 3? How do I typecast the command string to enum and handle the unknown commands in default case of switch?
A small variation of Joshua's solution is to add a dedicated case to the enumeration which is used for all unknown commands:
public enum Command:String {
case first = "FirstCommand"
case second = "SecondCommand"
// ...
case last = "lastCommand"
case unknown = "<unknownCommand>"
}
Now you can use the (failable) initializer Command(rawValue:)
together with the nil-coalescing operator ??
to map the incoming string
to an enumeration value, with all unknown commands being mapped
to .unknown
:
let command = Command(rawValue: incomingString) ?? .unknown
switch command {
case .first:
// Handle first command
case .second:
// Handle second command
case .last:
// Handle last command
case .unknown:
// Handle unknown command
}
It does not matter which raw string is used for case unknown
, so you
could also define
case unknown = "πΊπ©π»"
if you like. The compiler verifies that the string is different from
all other raw strings. And if the server happens to send that exact
string then it would be mapped to .unknown
.
To further expand the different ways you can solve this is by utilizing the CaseIterable protocol.
public enum Command:String, CaseIterable {
case first = "FirstCommand"
case second = "SecondCommand"
case last = "lastCommand"
case unknown = "UnknownCommand"
static func getCase(string:String) -> Command {
return self.allCases.first{"\($0.rawValue)" == string} ?? .unknown
}
}
The usage would be in this manner:
let textCommand = "SecondCommand"
let unknownCommand = "weirdCommand"
// What is the case label of the "textCommand"
print ("\(Command.getCase(string: textCommand))")
// The case label for our "unknownCommand" is
print ("\(Command.getCase(string: unknownCommand))")
You shift the usage of the null coalescing operator to the Command
enum instead.
It looks a bit overengineered and it probably is. Enjoy!
I'd attempt to create a Command
with a raw value of the incoming string, and only use the switch
if it succeeds. If it fails, then handle the unknown commands in another routine.
Like:
guard let command = Command(rawValue: incomingString) else {
handleUnknownCommand(incomingString)
return
}
switch command {
case first:
...
}
It depends on how you're working with it, but you could do something like this:
func getCommand(for string: String) -> Command {
switch string {
case Command.first.rawValue: return .first
case Command.second.rawValue: return .second
...
default: return .newCommand
}
}
I don't think it'd be possible to create new commands from the server in the return, but you could build a class with a command
property that takes a String
and works differently throughout the app.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With