swift小知识点之枚举

一,枚举的基本用法

  • 定义

    定义方向的枚举

    enum Direction {
       case north
       case south
      case east
       case west 
    }

    上面也可以写成

    enum Direction {
        case north, south, east, west
    }
  • 使用

    var dir = Direction.west 
    dir = Direction.east 
    dir = .north
    print(dir) // north

    也可以在switch中使用

    switch dir { 
      case .north:
          print("north") 
      case .south:
          print("south") 
      case .east:
          print("east") 
      case .west:
          print("west")
    }

    也可以进行场景对比

    if dir == .north {
        print("north")
    }

关联值

  • 有时将枚举的成员值跟其他类型的值关联存储在一起,会非常有用,可以认为将值直接存入到枚举的内存中

    enum Score {
        case points(Int)
        case grade(Character)
    }

    如下使用:

    var score = Score.points(88) 
    score = .grade("A")

    如果我们想使用枚举的具体值,可以如下用 i 来保存数据

    switch score {
      case let .points(i):
           print(i, "points") 
      case let .grade(i):
            print("grade", i)
    } 
    // grade A

    再比如我们想定义日期的枚举值,可以如下:

    enum Date {
        case digit(year: Int, month: Int, day: Int)
        case string(String)
    }
    //使用的时候,可以直接传年月日,或者传字符串
    var date = Date.digit(year: 2021, month: 9, day: 10) 
    date = .string("2021-09-10")
    
    switch date {
        case .digit(let year, let month, let day):
            rint(year, month, day) 
        case let .string(value):
            print(value)
    }
  • 必要时let也可以改为var

原始值

  • 枚举成员可以使用相同类型的默认值预先关联,这个默认值叫做:原始值

    定义枚举

    enum Grade : String {
        case perfect = "A"
        case great = "B"
        case good = "C"
        case bad = "D"
    }

    使用

    print(Grade.perfect.rawValue) // A 
    print(Grade.great.rawValue) // B 
    print(Grade.good.rawValue) // C 
    print(Grade.bad.rawValue) // D
  • 注意:原始值不占用枚举变量的内存

隐式原始值(Implicitly Assigned Raw Values)

如果枚举的原始值类型是Int、String,CGfloat, Swift会自动分配原始值

  • 原始值是 String 类型枚举值

    定义枚举值

    enum Direction : String {
       case north = "north"
        case south = "south"
        case east = "east"
        case west = "west"
    }

    等价于

    enum Direction : String {
        case north,south,east,west
    }

    使用

    print(Direction.north) // north 
    print(Direction.north.rawValue) // north
  • 原始值是 Int 类型枚举值

    定义

    enum Season : Int {
        case spring, summer, autumn, winter
    }

    结果

    print(Season.spring.rawValue) // 0 
    print(Season.summer.rawValue) // 1 
    print(Season.autumn.rawValue) // 2 
    print(Season.winter.rawValue) // 3
  • 如果自己指定了原始值
    定义
    enum Season : Int {
        case spring = 1, summer, autumn = 8, winter
    }

    结果

    print(Season.spring.rawValue) // 1 
    print(Season.summer.rawValue) // 2 
    print(Season.autumn.rawValue) // 8 
    print(Season.winter.rawValue) // 9

从原始值初始化

如果你用原始值类型来定义一个枚举,那么枚举就会自动收到一个可以接受原始值类型的值的初始化器(叫做 rawValue的形式参数)然后返回一个枚举成员或者 nil 。你可以使用这个初始化器来尝试创建一个枚举的新实例。

这个例子从它的原始值 7来辨认出 uranus :

let possiblePlanet = Planet(rawValue: 7)
// possiblePlanet is of type Planet? and equals Planet.Uranus

总之,不是所有可能的Int值都会对应一个行星。因此原始值的初始化器总是返回可选的枚举成员。在上面的例子中, possiblePlanet的类型是 Planet? ,或者“可选项 Planet”

注意

原始值初始化器是一个可失败初始化器,因为不是所有原始值都将返回一个枚举成员。

如果你尝试寻找有位置 11的行星,那么被原始值初始化器返回的可选项 Planet值将会是 nil:

let positionToFind = 11
if let somePlanet = Planet(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)")
}
// Prints "There isn't a planet at position 11"

这个例子使用可选项绑定来尝试访问一个原始值是 11 的行星。其中的 if let somePlanet = Planet(rawValue: 11)语句创建了一个可选项 Planet,而且如果 Planet的值可被取回的话,就将它赋给 somePlanet。在这种情况下,取回一个位置为 11的行星是不可能的,所以执行 else分支会被执行。

遍历枚举情况(case)

对于某些枚举来说,如果能有一个集合包含了枚举的所有情况就好了。你可以通过在枚举名字后面写 : CaseIterable 来允许枚举被遍历。Swift 会暴露一个包含对应枚举类型所有情况的集合名为 allCases 。下面是例子:

enum Beverage: CaseIterable {
    case coffee, tea, juice
}
let numberOfChoices = Beverage.allCases.count
print("\(numberOfChoices) beverages available")
// Prints "3 beverages available"

在上面的例子中,你写了一个 Beverage.allCases 来访问包含 Beverage 枚举所有情况的集合。你可以把 allCases 当成和其他任意集合——集合的元素就是枚举类型的实例,所以在这里就是 Beverage 的值。上面的例子计数了有多少个情况,然后下面的例子使用 for 循环来遍历所有情况。

for beverage in Beverage.allCases {
    print(beverage)
}
// coffee
// tea
// juice

上面例子中使用的语法是标记枚举遵循 CaseIterable 协议

属性和方法

  • 属性(只能是计算属性,其实也相当于方法)

    增加一个存储属性到枚举中不被允许,但你依然能够创建计算属性。当然,计算属性的内容都是建立在枚举值下或者枚举关联值得到的。
    enum Device {
        case iPad,iPhone
        var year:Int {
            switch self {
            case .iPhone: return 2007
            case .iPad : return 2010
        }
    }
  • 方法
    • 实例方法

      enum Device {
          case iPad, iPhone, AppleTV, AppleWatch
          func introduced() -> String {
              switch self {
              case .iPad: return "ipad"
              case .iPhone: return "iPhone"
              case .AppleTV:return "AppleWatch"
              case .AppleWatch:return "AppleTV"
              }
          }
      }
      print(Device.iPad.introduced())
      很清晰,我们定义了一个设备枚举,有iPad, iPhone, AppleTV, AppleWatch,还有一个介绍的方法。这里的introduced方法,你可以认为枚举是一个类,introduced是一个成员方法,Device.iPhone就是一个Device的实例,case们是他的属性,好了,有了这个对像,Device.iPhone可以认为,Device里面有一个匿名属性,现在设置这个属性为iPhone。好了,introduced里面的switch self,其实就是遍历这个匿名属性的所有场景,如iPad,iPhone等,然后根据不同的场景返回不同的值。
    • 静态方法

      enum Device {
          case iPad,iPhone,AppleTV,AppleWatch
          ///1. 实例方法
          func introduced() -> String {
              switch self {
              case .iPad: return "iPad"
              case .iPhone:return "iPhone"
              case .AppleTV:return "AppleWatch"
              case .AppleWatch:return "AppleTV"
              }
          }
          ///2. 静态方法
          static func fromSlang(term:String) -> Device? {
              if term == "iWatch" {
                  return .AppleWatch
              }
              return nil
          }
      }
      print(Device.fromSlang(term: "iWatch")!)

协议

Swift也允许你在枚举中使用协议(Protocols)和协议扩展(Protocol Extension)。
Swift协议定义一个接口或类型以供其他数据结构来遵循。enum当然也不例外。我们先从Swift标准库中的一个例子开始.
CustomStringConvertible是一个以打印为目的的自定义格式化输出的类型。

protocol CustomStringConvertible {
    var description:String{get}
}

该协议只有一个要求,即一个只读(getter)类型的字符串(String类型)。我们可以很容易为enum实现这个协议。

///协议
protocol CustomStringConvertible {
    var description:String{get}
}
///定义枚举
enum Trade:CustomStringConvertible {
case Buy(stock:String, amount:Int)
case Sell(stock:String,amount:Int)
    var description: String {
        switch self {
        case .Buy(stock:_ ,amount:_):
            return "Buy"
        case .Sell(stock:_ ,amount:_):
            return "Sell"
        }
    }
}
///打印
print(Trade.Buy(stock: "003100", amount: 100).description)

扩展

枚举也可以进行扩展。最明显的用例就是将枚举的case和method分离,这样阅读你的代码能够简单快速地消化掉enum内容,紧接着转移到方法定义:

///1.协议
protocol CustomStringConvertible {
    var description:String{get}
}

///2.定义枚举
enum Device {
    case iPad,iPhone,AppleTV,AppleWatch
}

///3.拓展枚举&遵守协议
extension Device:CustomStringConvertible {
    func introduced() -> String {
        switch self {
        case .iPad: return "ipad"
        case .iPhone: return "iPhone"
        case .AppleTV: return "AppleTV"
        case .AppleWatch: return "AppleWatch"
        }
    }
    
    var description: String {
        switch self {
        case .iPad: return "ipad"
        case .iPhone: return "iPhone"
        case .AppleWatch: return "AppleWatch"
        case .AppleTV: return "AppleTV"
        }
    }
}

print(Device.AppleTV.description)
print(Device.AppleTV.introduced())

泛型

///1.泛型枚举定义
enum Rubblish<T> {
    case price(T)
    func getPrice() -> T {
        switch self {
        case .price(let value):
            return value
        }
    }
}
///2.打印
print(Rubblish<Int>.price(100).getPrice())

posted on 2021-04-22 17:34  梁飞宇  阅读(134)  评论(0)    收藏  举报