Adding a Case to an Existing Enum with a Protocol

Adding a case to an existing enum with a protocol

Design

The work around is to use a struct with static variables.

Note: This is what is done in Swift 3 for Notification.Name

Below is an implementation on Swift 3

Struct:

struct Car : RawRepresentable, Equatable, Hashable, Comparable {

typealias RawValue = String

var rawValue: String

static let Red = Car(rawValue: "Red")
static let Blue = Car(rawValue: "Blue")

//MARK: Hashable

var hashValue: Int {
return rawValue.hashValue
}

//MARK: Comparable

public static func <(lhs: Car, rhs: Car) -> Bool {

return lhs.rawValue < rhs.rawValue
}

}

Protocol

protocol CoolCar {

}

extension CoolCar {

static var Yellow : Car {

return Car(rawValue: "Yellow")
}
}

extension Car : CoolCar {

}

Invoking

let c1 = Car.Red


switch c1 {
case Car.Red:
print("Car is red")
case Car.Blue:
print("Car is blue")
case Car.Yellow:
print("Car is yellow")
default:
print("Car is some other color")
}

if c1 == Car.Red {
print("Equal")
}

if Car.Red > Car.Blue {
print("Red is greater than Blue")
}

Note:

Please note this approach is not a substitute for enum, use this only when the values are not known at compile time.

Creating enum cases dynamically

One idea is to use a struct as an intermediary between data and the view controller. This struct can be created and used by a method like tableview's cell count; each time your view needs to know its layout, it constructs itself using whether or not there exists pending data.

enum Section: Int, CaseIterable {
case title, accounts, pending, total
}

struct SectionData {

var sections: [Section]

init(hasPendingData: Bool) {
if (hasPendingData) {
sections = Section.allCases
} else {
sections = [.title, .accounts]
}
}

}

class MyViewController: UIViewController {

var pendingModelData: Data?

func sectionCount() -> Int {
return SectionData(hasPendingData: pendingModelData != nil).sections.count
}

}

Going a step further, you could use didSet on pendingModelData to update the view displaying sections.

Swift - extend an enum for only one of its cases

Moved from comments:

I think here enum is not a best idea. You should try to do this with protocol + 3 classes/structs implementing it. That will allow you both extend "only one case" and add more "cases" in it. Like here.

Quick info about linked article:

Why I don’t love Swift Enums any more


At the last two Sydney Cocoaheads, any time I see a use of Enums in a talk, I make sure to ask “Why an enum and not a protocol?”. This blog post will hopefully explain the smell of enums.



Firstly, I have to say that enums are great if you never need to extend the number of cases. However, incorrect usages of enums break the O in SOLID Principles.

Open Close Principle


A Type should be open to extension, but closed for edits.

And I believe the Expression Problem best explains the violation.

The Expression Problem


Add new methods; add new cases. Pick one.

I will attempt to walk you through the Expression Problem with enums, then proceed to “solve” it with the Visitor Pattern.

Swift enum inheritance

In Swift language, we have Structs, Enum and Classes. Struct and Enum are passed by copy but Classes are passed by reference. Only Classes support inheritance, Enum and Struct don't.

So to answer your question, you can't have inheritance with Enum (and Struct types). Have a look here:

stackOverflow difference classes vs structs

How to design for a future additional enum value in protocol buffers?

Yes, the best approach is to make the first value in the enum something like UNKNOWN = 0. Then old programs reading a protobuf with an enum value they don't recognize will see it as UNKNOWN and hopefully they can handle that reasonably, eg by skipping that element.

If you want to do this you'll also want to make the enum be optional not required.

required, generally, means "I'd rather the program just abort than handle something it doesn't understand."

Note that it must be the first value declared in the proto source - just being the zero value doesn't make it the default.

Swift Enum associated values conforming to single protocol

I've found the solution in case anyone will need this too.

enum ContentType {
case content1(Type1 & Refreshable)
case content2(Type2 & Refreshable)
case content3(someLabel: Type3 & Refreshable)

func refreshMe() {
let caseReflection = Mirror(reflecting: self).children.first!.value
(caseReflection as? Refreshable)?.refresh() //If associated type doesn't have label

let refreshable = Mirror(reflecting: caseReflection).children.first?.value as? Refreshable
refreshable?.refresh() //If associated type has label
}
}

How to make an enum conform to Hashable with the API available in Xcode 10?

You can use autogenerated Hashable conformance, as proposed in the other answer (under condition your type doesn't contains any date of non-Hashable types).

But that's what you can do in the general case(autogenerated code would probably look like that too):

extension MyEnum: Hashable {

func hash(into hasher: inout Hasher) {

switch self {
case .caseOne(let value):
hasher.combine(value) // combine with associated value, if it's not `Hashable` map it to some `Hashable` type and then combine result
case .caseTwo(let value):
hasher.combine(value) // combine with associated value, if it's not `Hashable` map it to some `Hashable` type and then combine result
case .caseThree:
// you can `combine` with some `Hashable` constant, but here it's ok just to skip
break
}
}
}


Related Topics



Leave a reply



Submit