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.
Is it possible group & represent multiple cases as another case within an enum in Swift?
You can used nested Enum and a case with parameter
enum Devices {
case phone(iPhone)
case tablet(iPad)
enum iPhone {
case phone7
case phoneX
}
enum iPad {
case mini
case pro
}
}
let randomDevice = Devices.phone(.phone7)
switch randomDevice {
case .phone:
print("Its a phone")
default:
break
}
// prints "Its a phone"
Is it possible to assign multiple values in an enumeration? Swift language
No , enum can't have multiple raw values.But , you can use competed property like that
enum DollarCountries1{
case usa(String?)
var storedDollar : [String] {
["USA","Australia","Canada"]
}
var moneyType : String{
switch self {
case .usa(let str):
if storedDollar.contains(str!){
return "Dollar";
}
return "none"
default:
return "none"
}
}
}
let country = "USA"
var forUsa = DollarCountries1.usa(country)
print(forUsa.moneyType)
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 enum get the associated value of multiple case with same parameters in single switch-case
You can put multiple enum values in the same case
line, but you have to move the let
into the ()
:
var value: Double {
switch self {
case .width(let value), .height(let value), .xxxxx1(let value):
return value
}
}
You might want to put each enum
value on a separate line:
var value: Double {
switch self {
case .width(let value),
.height(let value),
.xxxxx1(let value):
return value
}
}
Unfortunately, that's about as elegant as it gets with enum
s with associated values. There's no way to get the associated value without explicitly listing the enum
s.
You can only combine values in the same line that have the same type of associated value, and all of the values have to bind to the same variable name. That way, in the code that follows, you know that the value
is bound and what its type is no matter which enum
pattern matched.
Multiple enum types list all cases
Here is a demo of possible solution. Prepared with Xcode 12.1 / iOS 14.1
enum Fish: String, CaseIterable {
case goldfish
case blueTang = "blue_tang"
case shark
}
func view<T: CaseIterable & Hashable>(for type: T.Type) -> some View where T.AllCases: RandomAccessCollection {
VStack(alignment: .leading) {
Text(String(describing: type)).bold()
ForEach(type.allCases, id: \.self) { item in
Text(String(describing: item))
}
}
}
struct FishDemoView: View {
var body: some View {
view(for: Fish.self)
}
}
How to pass an enum case into a function that uses 'if case' to check for a property's case
The answer of Shadowrun is a good start. Through the CasePaths library I found EnumKit, which was partially the inspiration for CasePaths. However it gives much simpler methods to compare cases. See my implementation below.
Using this library comes with some nice bonuses, it allows enums that have associated values to be made equatable by just comparing the cases and ignoring the values. This might not always be desired but come in quite handy in a lot of cases. I use it to compare ReSwift Actions with Associated values in my tests.
import Foundation
import EnumKit
class NonEquatableObject {
}
enum MyEnum: CaseAccessible { // <-- conform to CaseAccessible
case justACase
case numberCase(Int)
case stringCase(String)
case objectCase(NonEquatableObject)
}
let myArray: [MyEnum] = [.justACase, .numberCase(100), .stringCase("Hello Enum"), .justACase]
if case .justACase = myArray[0] {
print("myArray[0] is .justACase")
}
if case .numberCase = myArray[1] {
print("myArray[1] is .numberCase")
}
func checkCase(lhsCase: MyEnum, rhsCase: MyEnum) -> Bool {
if case lhsCase = rhsCase {
return true
} else {
return false
}
}
// Usage:
if checkCase(lhsCase: .justACase, rhsCase: myArray[0]) { //<-- allows to pass variables or just the cases (unfortunately not without associated value.)
print("myArray[0] is .justACase")
}
if case myArray[3] = myArray[0] { //<-- allows this here too
print("myArray[0] is .justACase")
}
// Bonus: Adding equatable if associated values are not equatable. Looking at the case only.
extension MyEnum: Equatable {
static func == (lhs: MyEnum, rhs: MyEnum) -> Bool {
lhs.matches(case: rhs)
}
}
if myArray[3] == myArray[0] {
print("myArray[3] == myArray[0]")
}
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.
Related Topics
Decoding a Nested Array in Swift 4
How to Access The Firebase Topics a User Is Subscribed To
Conversion Between Cgfloat and Nsnumber Without Unnecessary Promotion to Double
How to Assign a Generic Function to a Variable
Apple Turicreate Always Return The Same Label
Save/Copy a File from Bundle to Desktop Using Nssavepanel
Trying to Access Error Code in Alamofire
How to a Convert a Dictionary Slice to a Dictionary in Swift
How to Distinguish Bool and Int in Swift
Scenekit - Why Scnlight Created Automatically in Scnscene
How to Handle Error with Realm During Writing
Viewwilllayoutsubviews in Swift
How to Use Crc32 from Zlib in Swift (Xcode 9)
Iterating Through an Array of Strings, Fetched from Mongodb