I have been struggling to develop a code to avoid a big switch statement.
Basically I am given a set of tuples as input and now I would like to instantiate the appropriate class depending on the type specified in the tuple (first element of the tuple - e.g. ("Apple", ...)).
Currently I solved my problem by using a switch statement but this is a very bad idea if the number of classes increase in the future. Is there some elegant way to circumvent this issue?
Thank you!
class Apple {
var color = ""
}
class Banana {
var isTasty = false
}
let input = [("Apple", "green"),("Banana", "TRUE")]
for (type, value) in input {
switch type {
case "Apple":
Apple()
case "Banana":
Banana()
default:
print(value)
}
}
Check this out,
// Parent Class to group them
class Fruit {
var baseValue: Any
required init(_ this: Any) {
baseValue = this
(self as? Apple)?.color = this as! String
(self as? Banana)?.isTasty = this as! Bool
// You can add more subclasses here
}
}
class Apple: Fruit, Equatable {
var color = ""
func hash(into hasher: inout Hasher) {
hasher.combine(color)
}
static func == (lhs: Apple, rhs: Apple) -> Bool {
return lhs.color == rhs.color
}
}
class Banana: Fruit, Equatable {
var isTasty = false
func hash(into hasher: inout Hasher) {
hasher.combine(isTasty)
}
static func == (lhs: Banana, rhs: Banana) -> Bool {
return lhs.isTasty == rhs.isTasty
}
}
It's a little annoying that they have to conform to Fruit, Hashable, and Equatable. But it let's you do this, which answers your question:
let input: [(Fruit.Type,Any)] = [(Apple.self, "green"),(Banana.self, true)]
for (type, value) in input {
// Now you don't need that switch statement
let foo = type.init(value)
// Now you can use `as?` to find out what it is
print((foo as? Banana)?.isTasty)
// See, it prints `nil` first, then `Optional(true)` next.
// Which is how we want it to run
}
However, I think we can do even better.
enum Fruit {
case apple(color: String)
case banana(isTasty: Bool)
}
let input: [Fruit] = [.apple(color: "red"), .banana(isTasty: true)]
Much better.