I have a an array of enum cases, I wanna run a switch statement on these cases but getting this error: 'Enum case 'North' not found in type [Directions].
enum Directions {
case north
case west
case east
case south
static let all = [north, west, east, south]
}
class MyViewController {
var directions = Directions.all
func foo () {
switch directions {
case .north: // Error here ('Enum case 'North' not found in type '[Directions]')
print("Going north")
}
}
}
You first need to loop over the array and then you can use the switch
func foo () {
for direction in directions {
switch direction {
case .north: print("Going north")
case .west: print("Going west")
case .east: print("Going east")
case .south: print("Going south")
}
}
}
The name of the enum should be singular so Direction instead of Directions
the problem is that you are comparing a array of Directions type to an Directions enum case. You need to compare a particular element of array as listed below:
enum Directions {
case north
case south
case east
case west
static let all = [north, west, east, south]
}
class MyViewController {
var dir = Directions.all
func testing(){
switch dir[0] {
case .north:
print("north")
default:
print("default")
}
}
}
var a = MyViewController()
a.testing()
// out put : north
You can use the mention code in below way
enum Directions {
case north
case west
case east
case south
}
class MyViewController {
func foo () {
switch Directions
{
case Directions.north:
print("Going north")
}
}
}
Related
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)
How can I implement a protocol, or alternative solutions, to have in each case all those of the parameter. Something like League.teamA (.allCases)
import Cocoa
enum PlayerA: CaseIterable {
case center
case powerForward
case smallForward
}
enum PlayerB: CaseIterable {
case pointGuard
case shootingGuard
}
protocol EnumProtocol {
var description: String { get }
}
enum League: EnumProtocol {
case teamA(PlayerA)
case teamB(PlayerB)
}
extension League {
var description: String {
switch self {
case let .teamA(player):
switch player {
case .center: return "Center"
case .smallForward: return "Small Forward"
case .powerForward: return "Power Forward"
}
case let .teamB(player):
switch player {
case .pointGuard: return "Point Guard"
case .shootingGuard: return "Shooting Guard"
}
}
}
}
League.teamA(.smallForward).description
//League.teamA(.allCases)
//League.teamB(.allCases)
If you want to be able to pass both a single instance an an array of instances, the easiest solution is to declare the associated type as an array, since then you can pass an array with a single element in case you just want to pass a single instance, or you can pass allCases as well.
enum PlayerA: CaseIterable {
case center
case powerForward
case smallForward
}
extension PlayerA: CustomStringConvertible {
var description: String {
switch self {
case .center: return "Center"
case .smallForward: return "Small Forward"
case .powerForward: return "Power Forward"
}
}
}
enum PlayerB: CaseIterable {
case pointGuard
case shootingGuard
}
extension PlayerB: CustomStringConvertible {
var description: String {
switch self {
case .pointGuard: return "Point Guard"
case .shootingGuard: return "Shooting Guard"
}
}
}
protocol EnumProtocol {
var description: String { get }
}
enum League: EnumProtocol {
case teamA([PlayerA])
case teamB([PlayerB])
}
extension League: CustomStringConvertible {
var description: String {
switch self {
case let .teamA(players):
return players.description
case let .teamB(players):
return players.description
}
}
}
League.teamA([.smallForward]).description
League.teamA(PlayerA.allCases)
League.teamB(PlayerB.allCases)
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)
I want to determine if an enum is present in an enums list.
Intuitively I would do this:
if myEnum == (.one || .two) { return true }
else { return false }
Of course it doesn't work.
I know that I could do:
if myEnum == .one || myEnum == .two { return true }
else { return false }
Or
if [EnumType.one, EnumType.two].contains(myEnum) { return true }
else { return false }
But I just want to be fancy today :)
I am thinking about using filter but it seems overkill.
Do you have an idea?
Thanks a lot.
Thierry
You can do
//: Playground - noun: a place where people can play
import Cocoa
enum MyEnum {
case one
case two
case three
case four
}
let list: [MyEnum] = [.one, .two, .three, .four]
if list.contains(.one) {
// Contains
} else {
// Doesn't Contain
}
If you have associated data you have to make your enum be Equatable for this to work though. For example:
//: Playground - noun: a place where people can play
import Cocoa
enum MyEnum: Equatable {
case one
case two
case three
case four
case other(String)
static func ==(lhs: MyEnum, rhs: MyEnum) -> Bool {
switch (lhs, rhs) {
case (.one, .one),
(.two, .two),
(.three, .three),
(.four, .four):
return true
case (.other(let lhsString), .other(let rhsString)) where lhsString == rhsString:
return true
default:
return false
}
}
}
let list: [MyEnum] = [.one, .two, .three, .four, .other("test")]
if list.contains(.one) {
} else {
}
I would do a switch on each one and then have a default for if you can't find either of those types.
switch myEnum {
case .one:
print("One is here baby")
case .two:
print("Two is here baby")
default:
print("Can't find the case??????")
}
That's what OptionSet are for. It's technically a struct, but in usage, look very close to enum:
struct MyOptions : OptionSet {
var rawValue: Int
init(rawValue: Int) { self.rawValue = rawValue }
static let one = MyOptions(rawValue: 1)
static let two = MyOptions(rawValue: 2)
static let three = MyOptions(rawValue: 4)
}
let option: MyOptions = [.one, .two]
if option.contains([.one, .two]) {
print("Has one and two")
}
if !option.intersection([.one, .three]).isEmpty {
print("Has one or three")
}
I would use a switch as well and group the enum cases which are handled with common logic as follows:
enum MyEnum {
case one
case two
case three
case four
}
switch myEnum {
case .one, .two:
//deal with enum cases .one and .two
default:
//deal with all other cases
}
}
If you are trying to match arbitrary strings to various cases in your enum then you can do something like this (using Swift 3).
enum CompassPoint:String {
case north
case south
case east
case west
static func has(key: String) -> Bool {
for f in iterateEnum(CompassPoint.self) {
if(f.rawValue == key) {
return true;
}
}
return false;
}
private static func iterateEnum<T: Hashable>(_: T.Type) -> AnyIterator<T> {
var i = 0
return AnyIterator {
let next = withUnsafeBytes(of: &i) { $0.load(as: T.self) }
if next.hashValue != i { return nil }
i += 1
return next
}
}
}
CompassPoint.has(key: "south") // true
CompassPoint.has(key: "something") // false
Shoutout to #rintaro for his function for iterating over enums (found below).
https://stackoverflow.com/a/28341290/5270038
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