Enumeration - gpeegpee/learn-swift GitHub Wiki
This page describes enumeration used in swift language and summarize how to use enumeration properly in iOS programming.
- Definitions/Syntax
- Raw Value
- Associated Value
- A Swift enum can either have raw values or associated values.
- It’s because of the definition of a raw value: A raw value is something that uniquely identifies a value of a particular type. “Uniquely” means that you don’t lose any information by using the raw value instead of the original value. It’s formalized in Swift with the RawRepresentable protocol whose documentation states:
- Pros of Enum
- Enumerated data type makes the code self-documenting.
- Enumeration enables you to work with them in a type safe world.
- enumerated types can allow compilers to enforce semantic correctness.
- Swift enums allows you to use associated values for each case, even with different objects.
- Enums adopt many features, such as computed properties, custom init method, instance methods, generics, extensions etc.
- Swift/Case문에서 모든 케이스를 처리하도록 강제한다(컴파일 에러)
- Practices of enumeration
// An enumeration defines a common type for a group of related values and
// enables you to work with those values in a type-safe way within your code.
enum SomeEnumeration {
// enumeration definition goes here
}
//example with type
enum Gender :String{
case male
case female
}
enum Gender :String {
case male, female // in a single line like this, separated by commas
}
let test = Gender.male
print(type(of: Gender.self)) // Gender.Type
print(type(of: test)) // Gender
// Matching Enumeration Values with a Switch Statement
directionToHead = .south
switch directionToHead {
case .north:
print("Lots of planets have a north")
case .south:
print("Watch out for penguins")
case .east:
print("Where the sun rises")
case .west:
print("Where the skies are blue")
}
enum Gender {
case male = 1 //error: enum case cannot have a raw value if the enum does not have a raw type
case female
}
enum Genres:Int{
case One = 1001, Two = 2000, Three, Four, Five
}
print(Genres.Three.rawValue) // prints "2001"
enum WeekDay :String {
case Monday
case Tuesday
func day() ->String { return self.rawValue }
}
print(WeekDay.Monday.day()) // prints Monday
- only use String, Character, Integer, Floating Point, String, and Boolean for raw value
- Enum with raw value declaration also provides initializer on Enum to initialize case from raw value.
- this initialiser is failable, so the type of controlChar will be optional, because rawValue provide by you in initializer may not map to any value in Enum declaration.
// Raw Values
enum ASCIIControlCharacter: Character {
case tab = "\t"
case lineFeed = "\n"
case carriageReturn = "\r"
}
var controlChar = ASCIIControlCharacter(rawValue: “\t”)
print (type(of: controlChar)) // Optional<ASCIIControlCharacter>
if let test = controlChar {
print(test) // tab
}
// Implicitly Assigned Raw Values
enum PlanetRaw: Int {
case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
}
let earthsOrder = PlanetRaw.earth.rawValue
// earthsOrder is 3
enum CompassPointRaw: String {
case north, south, east, west
}
let sunsetDirection = CompassPointRaw.west.rawValue
// sunsetDirection is "West"
// Initializing from a Raw Value
let possiblePlanet = PlanetRaw(rawValue: 7)
let positionToFind = 11
if let somePlanet = PlanetRaw(rawValue: positionToFind) {
switch somePlanet {
case .earth:
print("Mostly harmless")
default:
print("Not a safe place for humans")
}
} else {
print("There isn't a planet at position \(positionToFind)")
}
enum Student {
case Name(String)
case Mark(Int,Int,Int)
}
var studDetails = Student.Name("Swift")
var studMarks = Student.Mark(98,97,95)
switch studMarks {
case .Name(let studName):
println("Student name is: \(studName).")
case .Mark(let Mark1, let Mark2, let Mark3):
println("Student Marks are: \(Mark1),\(Mark2),\(Mark3).")
default:
println("Nothing")
}
// Associated Values
enum Barcode {
case upc(Int, Int, Int, Int)
case qrCode(String)
}
var productBarcode = Barcode.upc(8, 85909, 51226, 3)
productBarcode = .qrCode("ABCDEFGHIJKLMNOP")
switch productBarcode {
case .upc(let numberSystem, let manufacturer, let product, let check):
print("UPC: \(numberSystem), \(manufacturer), \(product), \(check)")
case .qrCode(let productCode):
print("QR code: \(productCode).")
}
productBarcode = Barcode.upc(8, 85909, 51226, 3)
switch productBarcode {
case let .upc(numberSystem, manufacturer, product, check):
print("UPC : \(numberSystem), \(manufacturer), \(product), \(check).")
case let .qrCode(productCode):
print("QR code: \(productCode).")
}
Recursive enumerations
- Recursive Enumeration is an enumeration that has another instance of enumeration as associated value for one or more enumeration cases.
- Enumeration case is recursive is indicated by writing indirect before it, which tells compiler to insert necessary layer of indirection.
// Recursive Enumerations
enum ArithmeticExpression {
case number(Int)
indirect case addition(ArithmeticExpression, ArithmeticExpression)
indirect case multiplication(ArithmeticExpression, ArithmeticExpression)
}
indirect enum ArithmeticExpression2 {
case number(Int)
case addition(ArithmeticExpression2, ArithmeticExpression2)
case multiplication(ArithmeticExpression2, ArithmeticExpression2)
}
- This Enumeration can store three kinds of arithmetic expression — plain number, addition of two expressions, multiplication of two expressions.
- The addition and multiplication cases have associated values that are also arithmetic expressions — these associated values make it possible to nest expressions.
let five = ArithmeticExpression.number(5)
let four = ArithmeticExpression.number(4)
let sum = ArithmeticExpression.addition(five, four)
let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))
func evaluate(_ expression: ArithmeticExpression) -> Int {
switch expression {
case .number(let value):
return value
case let .addition(lhs, rhs):
return evaluate(lhs) + evaluate(rhs)
case let .multiplication(lhs, rhs):
return evaluate(lhs) * evaluate(rhs)
}
}
print(evaluate(product))
Nested Enum
enum Polygon {
enum Triangle: String {
case equilateral = "Has three equal sides"
case isosceles = "Has two equal sides"
case scalene = "Has no equal sides"
}
case quadrila_teral
case pentagon
case hexagon
}
Optional is enum type.
// Optional is enum type
enum Optional<Wrapped>
{
case none
case some(Wrapped)
}
// Optional long form
let color3 = Optional<ColorWithIntensity>.none
let color4 = Optional<ColorWithIntensity>.some(color2)
// Because Optionals are enumerations they can be tested with 'if case'
if case Optional<ColorWithIntensity>.none = color3
{
print("No ColorWithIntensity")
}
// tests if color4 is Optional<ColorWithIntensity>.some while ignoring
// the Wrapped associated value
if case Optional<ColorWithIntensity>.some(_) = color4
{
print("Some ColorWithIntensity exists")
}
// tests if color4 is Optional<ColorWithIntensity>.some, and if so assigns
// the wrapped associated value to the color variable
if case Optional<ColorWithIntensity>.some(var color) = color4
{
// because the color variable is of type ColorWithIntensity, an enumeration,
// we can use the 'if case' construct
if case ColorWithIntensity.red(var i) = color
{
print("Red \(i)")
}
else
{
print("Not Red")
}
}
Datasource of UI tableview
- we should be able to access an item by using its row index (indexPath.row) which is an integer.
- It should give a total count of items in it.
- we need to get a string representation of each item, so that we can display it in a label.
enum MenuList:Int, CustomStringConvertible {
case home = 0
case settings
case aboutUs
case needHelp
//Add further menu items here, if any
case countPlaceholder //Not a part of menu
static var count:Int{return MenuList.countPlaceholder.rawValue}
var description:String{
switch self {
case .home:
return "Home"
case .settings:
return "Settings"
case .aboutUs:
return "About Us"
case .needHelp:
return "Need Help?"
default:
return ""
}
}