Can I add enum value from another Swift enum? - swift

I have enum with volume types and enum of drink types
enum AlcoholVolumeType: String {
case portion30
case portion40
case portion50
case wineglass100
case wineglass125
case wineglass150
case glass175
case glass200
case glass300
case beerBottle330
case beerBottle355
case beerGlass400
case britishBank440
case americanPint473
case beerBottle500
case britishPint568
case bomber650
And drink enum
enum AlcoholType: String {
case champagne
case wineRed
case wineWhite
case winePink
case portWine
static var wineTypes: [AlcoholType] { [.champagne, .wineRed, .wineWhite, .winePink, .portWine] }
var isWine: Bool { AlcoholType.wineTypes.contains(self) }
case beerLight
case beerDark
case beerUnfiltered
case cider
case ale
Also i have custom drink types, so i need to add static value to enum with volume types
I tried to do this but i have an error
enum AlcoholVolumeType: String {
case \(AlcoholType)wineglass150
// Consecutive declarations on a line must be separated by ';'
}
I will try to explain in more detail
The application has the function of adding your own alcohol
If we have two types of custom alcohol, and the same containers are selected, then a bug occurs with the statistics, since it is calculated by the type of container, and we have one container for two types of alcohol, the following two screenshots show this
That is, I need to create a container type for each new type of alcohol so that one is not used for all, and there is no such bug in the statistics

Maybe you are talking about enums with associated values?
Something like this:
enum Wine {
case red
case white
case pink
}
enum Beer {
case light
case dark
case unfiltered
}
enum AlcoholType {
case wine(type: Wine)
case beer(type: Beer)
}
let alcohol: AlcoholType = .wine(type: .red)
switch alcohol {
case .wine(type: let type):
switch type {
case .red:
break
case .white:
break
case .pink:
break
}
case .beer(type: let type):
switch type {
case .light:
break
case .dark:
break
case .unfiltered:
break
}
}

Its hard to decide what do you need. If you need to store drink type and volume in one place - may be would be better to use structures and enums with associated values:
enum Wine: String {
case red
case white
case pink
}
enum Beer: String {
case light
case dark
case unfiltered
}
enum AlcoholType {
case wine(type: Wine)
case beer(type: Beer)
func getName() -> String {
switch self {
case .wine(type: let type):
return "\(type.rawValue) wine"
case .beer(type: let type):
return "\(type.rawValue) beer"
}
}
enum AlcoholVolumeType {
case glass(Int)
case portion(Int)
case bottle(Int)
}
struct Drink {
let alcohol: AlcoholType
let volume: AlcoholVolumeType
}
if you need to check matching - you can extend this struct:
struct Drink {
let alcohol: AlcoholType
let volume: AlcoholVolumeType
init?(alcohol: AlcoholType, volume: AlcoholVolumeType) {
guard validCombination(of: alcohol, volume) else { return nil}
let alcohol = alcohol
let volume = volume
}
func validCombination(of alcohol: AlcoholType, _ volume: AlcoholVolumeType) -> Bool {
switch (alcohol, volume) {
case (.wine(_), .glass(let size):
return (size == 100) || (size == 125)
default:
return false
}
}
func getDescription() -> String {
return alcohol.getName()
}
}
let validCase = Drink?(alcohol: .wine(.red), volume: .glass(100))
let imposibleCase = Drink?(alcohol: .wine(.red), volume: .portion(30))
print(validCase)
print(imposibleCase)

Related

Expression pattern of type 'Roll' cannot match values of type 'Requests.RawValue' (aka 'Roll')

I am trying to create an enum that returns a struct and I am not succeeding . I have checked a few questions similar to mine e.g here, and this here and they do not address the issue I have. This is my code:
import Foundation
struct Roll {
let times: String
init(with times: String) {
self.times = times
}
}
fileprivate enum Requests {
case poker
case cards
case slots
}
extension Requests: RawRepresentable {
typealias RawValue = Roll
init?(rawValue: RawValue) {
switch rawValue {
case Roll(with: "once"): self = .poker
case Roll(with: "twice"): self = .cards
case Roll(with: "a couple of times"): self = .slots
default: return nil
}
}
var rawValue: RawValue {
switch self {
case .poker: return Roll(with: "once")
case .cards: return Roll(with: "twice")
case .slots: return Roll(with: "a couple of times")
}
}
}
Then I would like to use it like : Requests.cards.rawValue
That's because of your structure Roll doesn't conform Equatable protocol and you're trying to make a comparison of it, just change it to
struct Roll: Equatable {
let times: String
init(with times: String) {
self.times = times
}
}

How can achieve Enum to have a arguments on a case

I have an enum which has a String raw value. I want one of the cases get a string as input and return a string which that input. How can I achieve this?
public enum PredictTypes: String {
case favtasks = "isFav == YES"
case importtanttasks = "isImportant == YES"
case alltasks = ""
case customList(listName: String) = "listName == \(listName)"
}
As I searched I found some posts but can't understand for my case:
Can associated values and raw values coexist in Swift enumeration?
I would rewrite your enum like this:
public enum PredictTypes {
case favtasks
case importanttasks
case alltasks
case customList(listName: String)
var rawValue: String {
switch self {
case .favtasks: return "isFav == YES"
case .importanttasks: return "isImportant == YES"
case .alltasks: return ""
case .customList(let listName): return "listName == \(listName)"
}
}
}

Swift very long enum with one different case: how to deal with that?

I try to make enum from HTML colours. First moment I thought it will be nice and simple but I hit a wall. Colors could be defined as name: moroon, gray, grey (same value) or RGBA string #00000000. I started from:
enum HTMLColor {
case aliceblue
case antiquewhite
case aqua
case aquamarine
case azure
//..... many, many names and at the end:
case custom(String)
}
OK. Because of last custom and some double names (gray, grey) I cannot define raw type. So I added two long switches name and hexString:
public var name:String {
switch self {
case .aliceblue: return "aliceblue"
case .antiquewhite: return "antiquewhite"
case .aqua: return "aqua"
case .aquamarine: return "aquamarine"
case .azure: return "azure"
//..... many, many names and at the end:
case .custom(let string): return string
}
}
Similar with hexString – but in place of name I can return "#00000000".
But now I have not idea how to implement init(from string:String) or init(from decoder:Decoder). I would like to have
let azure = HTMLColor(from: "azure")
and got .azure
or:
let custom = HTMLColor(from: "#AB0023FF")
and got .hexString(hexValue) to use them as:
switch color {
case .custom(let string): makeRealColorFromString(string)
default: makeRealColorFromString(color.hexString)
}
Maybe enum is not a best idea for this particular problem?
You can use struct for this. Like this:
struct HTMLColor: RawRepresentable, Codable {
typealias RawValue = String
var rawValue: String
}
And then you can add color cases anywhere you want and whichever you want:
extension HTMLColor {
static let aliceblue = HTMLColor(rawValue: "aliceblue")
static let antiquewhite = HTMLColor(rawValue: "antiquewhite")
static let aqua = HTMLColor(rawValue: "aqua")
static let aquamarine = HTMLColor(rawValue: "aquamarine")
static let azure = HTMLColor(rawValue: "azure")
//..... many, many names, and even:
static let customBlack = HTMLColor(rawValue: "#00000000")
}
And now you can use HTMLColor.azure or do let custom = HTMLColor(rawValue: "#AB0023FF") anywhere in your code.
And for RawRepresentable default encoding/decoding would be in/from RawValue type (here it's String).
As others have noted, enum (although intuition suggests so) may be not the best option for implementing this. Having said that, if you do want to use an enum you could do something like this:
enum HTMLColor: CaseIterable, ExpressibleByStringLiteral {
case white
case black
// ... others
case custom(String)
static var allCases: [HTMLColor] {
return [.white, .black] // All except .custom here
}
var name: String {
switch self {
case .white: return "white"
case .black: return "black"
// ... others
case .custom(let string): return string
}
}
var hexString: String {
switch self {
case .white: return "#FFFFFFFF"
case .black: return "#00000000"
// ... others
case .custom(let string): return string
}
}
init(stringLiteral: String) {
self = HTMLColor.allCases.first(where: { ($0.name == stringLiteral) || ($0.hexString == stringLiteral) }) ?? .custom(stringLiteral)
}
}
Essentially, we conform to ExpressibleByStringLiteral which means that we can initialize our enum with a string literal. Then in the initializer, we search names & hexValues for a match or return a .custom
It's not a complete or a production-ready solution by any means (one obvious thing that is missing is that it doesn't match hex values that omit the alpha component or the '#' prefix) but you get the idea...
Then we can use it like this:
let c1: HTMLColor = "#FFFFFFFF"
let c2: HTMLColor = "#F2F2F2FF"
let c3: HTMLColor = "black"
print(c1) // --> .white
print(c2) // --> .custom("#F2F2F2FF")
print(c3) // --> .black
Finally, you could even extend support for Int literal initalization (so you could do let c: HTMLColor = 0xF2F2F2FF for example) or tackle all code repetition with tools like Sourcery

How to check Swift nested enums for equality of the outer enum only?

I'm trying to use nested enums to describe my model, in a way that makes illegal states impossible and provides categorisation at the top level. Right now, my (simplified) code is:
enum SportsEvent {
enum RunningEvent {
case sprint
case marathon
}
enum ThrowingEvent {
case hammer
case javelin
case discus
}
case running(event: RunningEvent)
case throwing(event: ThrowingEvent)
func isSameCategory(as other: SportsEvent) -> Bool {
return false
}
}
let sprint = SportsEvent.running(event: .sprint)
let javelin = SportsEvent.throwing(event: .javelin)
let hammer = SportsEvent.throwing(event: .hammer)
sprint.isSameCategory(as: javelin) // False
hammer.isSameCategory(as: javelin) // True
It feels like it should be trivial with an if case ... and a wildcard, but I'm not seeing how to achieve that. I'm hoping a giant switch statement isn't necessary, as my actual model is more complex.
I think you need a switch-statement, with a “compound case” listing all
possible “same value combinations” of the outer enumeration,
plus a default case:
func isSameCategory(as other: SportsEvent) -> Bool {
switch (self, other) {
case (.running, .running),
(.throwing, .throwing):
return true
default:
return false
}
}
Or (attribution goes to #Hamish):
func isSameCategory(as other: SportsEvent) -> Bool {
switch (self, other) {
case (.running, .running),
(.throwing, .throwing):
return true
case (.running, _),
(.throwing, _):
return false
}
}
which has the advantage that the compiler checks that all cases are covered. For an enumeration with n cases that makes 2 * n
cases in the switch statement (which is better than n * n if you checked all possible combinations).
Depending on your use case, you might be able to convert SportEvent to a protocol:
enum RunningEvent {
case sprint
case marathon
}
enum ThrowingEvent {
case hammer
case javelin
case discus
}
enum SportEventCategory {
case running
case throwing
}
protocol SportEvent {
var category: SportEventCategory { get }
}
extension RunningEvent: SportEvent {
var category: SportEventCategory {
return .running
}
}
extension ThrowingEvent: SportEvent {
var category: SportEventCategory {
return .throwing
}
}
let sportEvent1: SportEvent = RunningEvent.sprint
let sportEvent2: SportEvent = ThrowingEvent.hammer
print(sportEvent1.category == sportEvent2.category)
or even as one flat enum:
enum SportEvent {
enum Category {
case running
case throwing
}
case sprint
case marathon
case hammer
case javelin
case discus
var category: Category {
switch self {
case .sprint, .marathon, .hammer:
return .running
case .javelin, .discus:
return .throwing
}
}
}
let sportEvent1: SportEvent = .sprint
let sportEvent2: SportEvent = .marathon
print(sportEvent1.category == sportEvent2.category)

Swift enum both a string and an int

I have a situation where I'm trying to do binary decoding of some data and the data types have both a numerical value and a string value and a name. I was thinking of using an enum such as:
enum TARGET_TRACK_TYPE : String {
case TT_INVALID = "Invalid"
case TT_TRUE_TRACK_ANGLE = "True Track Angle"
case TT_MAGNETIC = "Magnetic"
case TT_TRUE = "True"
}
However I also know that:
TT_INVALID = 0 and TT_TRUE_TRACK_ANGLE = 1, etc. Is there an easy way to encapsulate both these "things" the string and the numerical value into an enum construct or do i need to make some sort of struct/class to handle this?
I guess I'd like to do something like
let a = TARGET_TRACK_TYPE.rawValue(value: 2)
println(a)
which would print True Track Angle
Again, I know this can be done with a struct or a class but I'm specifically interested in the enum
Or for another example:
/// Emitter Category is defined in section 3.5.1.10 of the GDL90 Spec
struct EmitterCategory {
let category : Int
func getString() -> String {
switch(category) {
case 0:
return "No aircraft type information";
case 1:
return "Light";
case 2:
return "Smalle";
case 3:
return "Large";
case 4:
return "High Vortex Large";
case 5:
return "Heavy";
case 6:
return "Highly Manuverable";
case 7:
return "Rotorcraft";
case 8:
return "(Unassigned)";
case 9:
return "Glider/sailplane";
case 10:
return "Ligther than air";
case 11:
return "Parachutist/sky diver";
case 12:
return "Ultra light/hang glider/paraglider";
case 13:
return "(Unassigned)";
case 14:
return "Unmanned aerial vehicle";
case 15:
return "Space/transatmospheric vehicle";
case 16:
return "(Unassigned)";
case 17:
return "Surface vehicle - emergency vehicle";
case 18:
return "Surface vehicle - service vehicle";
case 19:
return "Point obstacle";
case 20:
return "Cluster Obstacle";
case 21:
return "Line Obstacle";
default:
return "(reserved)";
}
}
}
Is there a way to refactor this struct into an enum such that I construct the enum with an integer value but I "read" the enum as a string? I'm pretty sure the answer is no.
I think this will do it for me. Thank you self.. :)
protocol GDL90_Enum {
var description: String { get }
}
enum TARGET_ADDRESS_TYPE : Int, GDL90_Enum {
case ADSB_ICAO_ADDRESS = 0
case ADSB_SELF_ADDRESS = 1
case TISB_ICAO = 2
case TISB_TRACK_ID = 3
case SURFACE_VEHICLE = 4
case GROUND_STATION = 5
var description: String {
switch self {
case .ADSB_ICAO_ADDRESS:
return "ADS-B with ICAO address"
case .ADSB_SELF_ADDRESS:
return "ADS-B with Self-assigned address"
case .TISB_ICAO:
return "TIS-B with ICAO address"
case .TISB_TRACK_ID:
return "TIS-B with track file ID"
case .SURFACE_VEHICLE:
return "Surface Vehicle"
case .GROUND_STATION:
return "Ground Station Beacon"
default:
return "Reserved"
}
}
}
With Swift 4.2 this can be done using CaseIterable. One, relatively concise way is to do the following
enum Directions: String, CaseIterable {
case north, south, east, west
static var asArray: [Directions] {return self.allCases}
func asInt() -> Int {
return Directions.asArray.firstIndex(of: self)!
}
}
print(Directions.asArray[2])
// prints "east\n"
print(Directions.east.asInt())
// prints "2\n"
print(Directions.east.rawValue)
// prints "east\n"
You should use RawRepresentable
#objc enum AppEvent:Int, RawRepresentable {
case appLaunch
case homeScreen
public typealias RawValue = String
public var rawValue: RawValue {
switch self {
case .appLaunch : return "appLaunch"
case .homeScreen : return "homeScreen"
}
public init?(rawValue: RawValue) {
switch rawValue {
case "appLaunch" : self = .appLaunch
case "homeScreen" : self = .homeScreen
}
Have you considered using a dictionary?
let targetTrackDict: [Int: String] =
[99: "Invalid",
1: "True Track Angle",
2: "Magnetic",
5: "True"]
Note the number codes don't have to be ordered or contiguous. Being specific about the dictionary's type in its declaration prevents a lot of warnings or errors in the following snippets.
Getting the name for a code is easy:
var code = 2
if let name = targetTrackDict[code] {
print("\(name) has code \(code)")
} else {
print("\(code) is not a valid track type")
}
I haven't found a tidy way of getting the code for a name, but this does it:
let magneticCode = targetTrackDict.first(where:
{key, value in value == "Magnetic"})?.key
// returns an optional
and you would of course dress it up as a function. What you don't get automatically is an internal name for your track type, but do you need one? And the line above does it for you in a way.
Summing up #Jeef's answer and #NobodyNada's comment, here's a solution
public enum Animal: Int, CustomStringConvertible {
case Dog, Cat
public var description: String {
switch self.rawValue {
case 0: return "Dog"
case 1: return "Cat"
default: return ""
}
}
}
var animal = Animal.Dog
print(animal) // Dog