I have multiple enums which will all share an identical function. Is there a way to write this function once and have it present in all specified enums? Here is an example:
enum CustomerTypes: Int, CaseIterable {
case NewCustomer = 0
case ExistingCustomer
case Myself
private var title: String {
switch self {
case .NewCustomer : return StandardStrings.NewDrive.NewCustomer.string
case .ExistingCustomer : return StandardStrings.NewDrive.ExistingCustomer.string
case .Myself : return StandardStrings.NewDrive.Myself.string
}
}
static var titles: [String] {
get {
var toReturn: [String] = []
for value in allCases {
toReturn.append(value.title)
}
return toReturn
}
}
}
enum EnquiryTypes: Int, CaseIterable {
case Phone = 0
case FaceToFace
private var title: String {
switch self {
case .Phone : return StandardStrings.Misc.Phone.string
case .FaceToFace : return StandardStrings.Misc.FaceToFace.string
}
}
static var titles: [String] {
get {
var toReturn: [String] = []
for value in allCases {
toReturn.append(value.title)
}
return toReturn
}
}
}
As you can see here, both enums share identical "titles" variables. Is there a way I can possibly create an enum/class in which they can inherit this function from?
Here are some things I have tried:
Can you extend an enum?
I considered this, but I don't want to extend ALL functions that have Int rawValues
I considered creating a protocol, then creating a function which took the protocol like this, but I still would need to implement the _allCases on every enum (as you can't inherit from CaseIterable):
protocol RBEnum {
var title: String { get }
var _allCases: [RBEnum] { get }
}
So any ideas how I can avoid violating DRY principles on these enums?
A protocol is the right approach. Not sure why do you think protocols cannot inherit from each other, but they can, so you can make your protocol inherit from CaseIterable
.
You can also significantly simplify titled
by using map
instead of a for..in
loop and getting rid of the useless get
specifier. A getter is the default accessor for a computed property, you don't need to wrap your closure in get { ... }
unless you are creating both a getter and a setter.
protocol Titled: CaseIterable {
var title: String { get }
static var titles: [String] { get }
}
extension Titled {
static var titles: [String] { allCases.map(\.title) }
}
Then you just need to keep the title
property on your enums and make them conform to Titled
and due to the default implementation you get titles
for free.
Unrelated to your question, but enum cases should be lowerCamelCase like all variables.
enum CustomerTypes: Int, Titled {
case newCustomer = 0
case existingCustomer
case myself
var title: String {
switch self {
case .newCustomer : return "new"
case .existingCustomer : return "existing"
case .myself : return "my"
}
}
}
enum EnquiryTypes: Int, Titled {
case phone = 0
case faceToFace
var title: String {
switch self {
case .phone : return "phone"
case .faceToFace : return "face"
}
}
}