Swift枚舉

CObjective-C中的枚舉相比,Swift枚舉功能更強大。它支持很多只有才有的特性,如:PropertiesMethods、Initialization、 ExtensionsProtocols...

  • C語言枚舉的寫法

只支持Int一種類型:

// WEEK:枚舉名,可省略
// MON:枚舉成員
// week:定義枚舉變量
enum WEEK {
    MON, TUE, WED, THU, FRI, STA, SUN
} week;
  • Swift枚舉寫法

支持整型(Integer)、浮點數(Float Point)、字符串(String)布爾類型(Boolean)四種基本類型,如果想要支持其它自定義的類型,需實現 StringLiteralConvertible 協議:

enum WEEK {
   case MON, TUE, WED, THU, FRI, STA, SUN
}
// 或者
enum WEEK {
   case MON
   case TUE
   case WED
   case THU
   case FRI
   case STA 
   case SUN
}

通過查看變量的內存可知:Swift枚舉成員case是一個整型值即它所在的index,且只占1個字節(UInt8)。

若標明類型String,則表示rawValueString類型,而case成員的類型。

enum WEEK : String {
   case MON = "MON"
   case TUE = "TUE"
   case WED = "WED"
   case THU = "THU"
   case FRI = "FRI"
   case STA = "STA"
   case SUN = "SUN"
}

case后面的"MON"就是枚舉值; "="后面的"MON"rawValue(原始值 )
Swift隱式rawValue分配:不寫"="及后面的字符串,即:

enum WEEK : String {
   case MON 
   case TUE 
   case WED 
   case THU 
   case FRI
   case STA 
   case SUN 
}
  • 定義枚舉變量

var w = WEEK.MON

一旦w的類型被聲明為WEEK,則可以使用一個縮寫語法(.)將其設置為WEEK的值,即:

var w : WEEK = .TUE

標明類型后,可以通過w.MON.rawValue獲取原生值rawValue,本質是調用rawValueget();未標明類型則不能獲取rawValue。

// 前提是標明了rawValue的類型,才能獲取rawValue
var w = WEEK.MON.rawValue

通過SIL看一下區別:這里標明的類型是Int

未標明類型的SIL

可知標明類型能調用rawValue的本質是:rawValue是一個計算屬性,通過調用其get()獲取該屬性的;而在rawValueget()中,rawValueInt類型時默認從0開始,是String類型時默認是枚舉成員本身的字符串:

rawValue類型為Int的get()方法實現.png
rawValue類型為String的get()方法實現.png

那么當類型為String時,get()中構建的字符串存放在哪里呢?

隱式rawValue構建的字符串在MachOView中的存放位置

可知:隱式rawValue字符串編譯過程中就已經存放在MachOView文件中的__Text,__cstring中,且通過字符串的地址可知占用的是一段連續的內存空間。

  • 枚舉變量rawValue的區別

print(WEEK.THU) //THU
print(WEEK.THU.rawValue) //THU

在這里,雖然打印出來的都是THU,但需要區分的是WEEK.THUWEEK類型的,而WEEK.THU.rawValueString類型的。

  • 枚舉中init?( )

  1. 先來看看什么情況下才會調用枚舉的初始化方法?

可知只有通過WEEK(rawValue:)這種方式才會調用到init()方法。

  1. 分析枚舉的初始化方法:

_allocateUninitializedArray:創建一個元組
第一個元素:與枚舉個數大小一樣的數組,用于存儲枚舉中的rawValue,在本例中是StaticString--->Array<StaticString>
第二個元素:數組的首地址--->BuildIn.RawPointer

_findStringSwitchCase:查找指定枚舉值在數組中的位置,返回index。

0count-1依次與index作比較:

  • 如果相等構建對應的枚舉
  • 如果不相等則構建一個Optional.none!enumelt的枚舉
  • 關聯值

enum Shape {
    case circle(radius:Double)
    case rectangle(length:Int, width:Double, height:Int)
}

// 創建枚舉的關聯值
var shape = Shape.circle(radius: 3.00)
// 重新分配關聯值
shape = Shape.circle(radius: 2.0)

此時的枚舉值不再有rawValue,也沒必要(rawValue是單個值),而關聯值可以是一組值
通過SIL也可以看出:enum再有初始化方法以及計算屬性rawValue。

SIL中的有關聯值的enum

關聯值的標簽可省略,只寫類型(不推薦,可讀性差),如:

enum Shape {
    case circle(Double)
    case rectangle(Int, Double, Int)
}
  • 枚舉的用法:模式匹配

  1. 簡單用法
enum WEEK : String {
    case MON
    case TUE
    case WED
    case THU
    case FRI
    case STA
    case SUN
}

var currentDay : WEEK = WEEK.SUN
var str : String
switch currentDay {
    case .STA, .SUN:
        str = "Happy Day"
    default:
        str = "Sad Day"
}

SIL的實現:通過匹配case來做相應的代碼跳轉。

2.復雜用法:匹配關聯值

可以通過SIL文件知道:

  • case let .circle(radius):中的 let 表示關聯值是一個常量,不可被修改;也可換一種寫法case .circle(let radius):。
  • case .rectangle(let length, var width) :var width表示 width 是一個變量,可以被修改;如果關聯值width用不到則可以用_代替,即case .rectangle(let length, _) :。
  • 若只想匹配單個case可以:
if case let Shape.circle(radius) = shape {
    tempValue = radius
}
  • 如果只關心不同的case相同關聯值,可以這樣寫:
enum Shape {
    case circle(radius:Double)
    case rectangle(length:Double, width:Double)
    case square(length:Double, width:Double)
}

var rectangle = Shape.rectangle(length:5, width: 3)
var square = Shape.square(length: 9, width: 5)
var tempValue : Double

switch square {
case let .rectangle (5, x), let .square(x, 5):
    tempValue = x
default :
    tempValue = 0.0
} 
// 若switch rectangle {..}則tempValue=3
// 若switch square {..}則tempValue=9

還可以使用通配符的方式:

case let .rectangle (_, x), let .square(x, _):
print(x)
// 若switch rectangle {..}則 3
// 若switch square {..}則 9
//或者
case let .rectangle (x, y), let .square(y, x):
print(x,y)
// 若switch rectangle {..}則 (5,3)
// 若switch square {..}則 (5,9)

底層實現還是通過匹配case,匹配成功后取出元組中x所在的元素,將該元素賦值給x,再將元素值賦值給tempValue

  • 枚舉的嵌套

  1. 枚舉中嵌套枚舉
enum CombineDirect {
    enum BaseDirect {
        case up
        case down
        case left
        case right
    }
    case leftUp(direct1:BaseDirect, direct2:BaseDirect)
    case rightUp(direct1:BaseDirect, direct2:BaseDirect)
    case leftDown(direct1:BaseDirect, direct2:BaseDirect)
    case rightDown(direct1:BaseDirect, direct2:BaseDirect)
}

var direct = CombineDirect.leftDown(direct1: .left, direct2: .right)
  1. 結構體中嵌套枚舉
struct Skill {
    enum Direct {
        case up
        case down
        case left
        case right
    }
    
    var direct : Direct
    func launchSkill() {
        switch direct {
            case .left, .right:
                print("控制方向")
            case .up, .down:
                print("移動距離")
        }
    }
}
  • 枚舉中包含屬性

枚舉本身是類型,只能包含計算屬性(只有方法,不存儲在enum中)和類型屬性(也不存儲在enum中),能包含存儲屬性。
注意:結構體可以有存儲屬性,結構體大小就是存儲屬性的大小。

  • 枚舉中包含方法

enum WEEK : Int {
    case MON
    case TUE
    case WED
    case THU
    case FRI
    case STA
    case SUN
    
    func nextDay()-> WEEK{
        switch self {
        case .SUN:
            return .MON
        default:
            return WEEK(rawValue: self.rawValue + 1) ?? self
        }
    }
}
  • 迭代枚舉

如果需要迭代枚舉中的所有值時,需要自定義的枚舉遵守CaseIterable協議,通過獲取enum的allCases屬性獲取所有值:

enum FlowerType: CaseIterable {
    case Rose
    case Orchid
    case Peony
}

let numOfFlowerType = FlowerType.allCases.count
for flower in FlowerType.allCases {
    print(flower)
}
//Rose
//Orchid
//Peony
  • 枚舉中可使用協議

protocol CustomDesc {
    var description : String { get }
}

enum FlowerType: CustomDesc {
    case Rose
    case Orchid
    case Peony
    
    var description: String {
        switch self {
        case .Rose:
            return "Rose"
        case .Orchid:
            return "Orchid"
        case .Peony:
            return "Peony"
        }
    }
}
  • 枚舉可擴展

枚舉通過擴展case(放在枚舉中)和方法(放在枚舉的擴展中)分離

enum FlowerType {
    case Rose
    case Orchid
    case Peony
}

extension FlowerType {
    func introduced() -> String {
        switch self {
        case .Rose:
            return "Rose"
        case .Orchid:
            return "Orchid"
        case .Peony:
            return "Peony"
        }
    }
}
  • 枚舉可使用泛型

枚舉通過泛型參數定義以適應枚舉中的關聯值(可有多個泛型參數),拿Swift標準庫中的Optional類型為例:

enum Optional<Wrapped> {
    case none
    case some(Wrapped)
}

let aValue = Optional<Int>.some(5)
let noValue = Optional<Int>.none
if noValue == Optional.none { print("No value")
  • 枚舉的大小

1.只有一個case的簡單枚舉(其實無意義):

enum test {
  case a
}
print(MemoryLayout<test>.size) //0
print(MemoryLayout<test>.stride) // 1
  1. 有多個case的
enum test {
  case a
  case b
  case c
  case d
}
print(MemoryLayout<test>.size) // 1
print(MemoryLayout<test>.stride) // 1

enum其實就是以1字節的長度存儲在內存中即UInt8,當case個數超過UInt8的最大值255個時,編譯器自動將enum的內存大小UInt16。也可在匯編模式下看出:每次移動1個字節。

var tmp = test.a時
var tmp = test.b時

總結:原始值的enum大小取決于case的數量,與rawValue類型無關,case超不過255個就是 UInt8--->1字節,如果超過則自動升級成UInt16

  1. 關聯值的枚舉:大小取決于case中最大內存的大小以及字節對齊

PS:是否+1還沒弄透徹,下次弄明白了再補上...,這里先記錄一下自測總結出來的結果,可能有誤...(可略過)

猜想1: enum去占最大內存的case外:
有占大于等于最大關聯值類型a(>8視為8,<8就是a本身)的case的話,size就需要在對齊基礎上+1(case的大?。?br> 小于最大關聯值類型a字節則需要+1。

 enum Shape {
     case circle(radius:UInt8) //1
     case rectangle(length:UInt8, width:Int, height:UInt16) // 1   8   2
     case square(width:Int32, height:Int32) // 4  4
 }  // size : 19

 enum Shape {
     case circle(radius:UInt8)
     case rectangle(length:UInt8, width:Int, height:UInt16)
     case square(width:UInt8, height:UInt16)
 }  // size : 18

size:除去最大的rectangle(字節對齊的原則上其大小為8 + 8 + 2 = 18),circlesquare中只要任一個所占內存大于等于enum中的最大類型(這里所有的case中最大的是Int為8字節),該enum的size大小都需要在對齊基礎+ 1(case的大小);
這里circle只占了1個字節,而在上面的enum中square占4 + 4 等于8字節,所以需要+1 = 19,下面的enum中square占1 + 2 = 3小于8字節,不需要+1。

猜想2: case數量>1的前提下, 最大case只有一個關聯值時始終+1。

stride:為了字節對齊(空間換取時間,提高效率),需要將實際大小補齊到最大所占內存大小(這里是Int-->8)的倍數,所以19補齊成8的倍數即3 * 8 = 24

  1. 枚舉嵌套枚舉的大小
    比較特殊:取決于內層枚舉的大小字節對齊

5.嵌套枚舉的結構體的大小 :取決于存儲屬性的內存大?。ㄓ袥]有方法都一樣,因為方法存在結構體中)
有存儲屬性時size為1、stride為1
無存儲屬性時size為0、stride為1 (空結構體也是size為0、stride為1 )

  • 區分內存對齊字節對齊
    內存對齊:64位下8字節對齊,分配對象時用到內存對齊。
    字節對齊:對齊的目的就是地址要從偶地址開始,成員變量的起始位要從該變量內存大小的倍數開始。

下面兩個結構體,不同類型的成員變量交換位置都會導致結構體的內存大小不一致。

struct A {
    var height : Double  //8
    var count : UInt16   //2
    var age : UInt8        //1
}

print(MemoryLayout<A>.size) //11
print(MemoryLayout<A>.stride)  //16

struct B {
    var height : Double  //8
    var age : UInt8        //1
    var count : UInt16   //2
}

print(MemoryLayout<B>.size) //12
print(MemoryLayout<B>.stride)  //16
結構體A的內存存放
結構體B的內存存放

OC的結構體內存對齊規則如下:

  • struct的第一個數據成員要從偏移量offset為0的位置開始,后面的其他成員的起始的位置要從該成員類型的字節大小(Swift中>8的視為8)的整數倍開始

  • 步長是最大成員類型(Swift中>8的視為8)的整數倍

  • 若一個結構體包含另一個結構體的成員,結構體成員要從自身結構體中最大類型(Swift中>8的視為8)的整數倍開始

  • indirect關鍵字

  1. 使用場景:用遞歸的方式表達想要的數據結構
使用`嵌套枚舉`表達`鏈表`的結構

上面圖片中是一個遞歸枚舉,若不用indirect關鍵字聲明編譯器會報錯,所以下面case需要用indirect關鍵字聲明:

遞歸枚舉

原因:普通枚舉大小在編譯時期就確定好的,而這里的遞歸枚舉大小在編譯時是未知的,所以需要用indirect關鍵字來說明需要在堆上分配一塊內存空間來存放,當前case會使用引用類型存儲。

  1. 本質:在上分配一塊內存,存儲一個指向case的值地址
遞歸枚舉的內存結構

定義一個簡單的遞歸枚舉變量,分析SILindirect關鍵字到底做了些什么事情?

var list = List<Int>.node(4, List<Int>.end)
// main
sil @main : $@convention(c) (Int32, UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>) -> Int32 {
bb0(%0 : $Int32, %1 : $UnsafeMutablePointer<Optional<UnsafeMutablePointer<Int8>>>):
  alloc_global @main.list : main.List<Swift.Int>        // id: %2
  %3 = global_addr @main.list : main.List<Swift.Int> : $*List<Int> // user: %16
  %4 = metatype $@thin List<Int>.Type
  // 構建Int類型的值4
  %5 = integer_literal $Builtin.Int64, 4          // user: %6
  %6 = struct $Int (%5 : $Builtin.Int64)          // user: %13
  %7 = metatype $@thin List<Int>.Type
  %8 = enum $List<Int>, #List.end!enumelt         // user: %14
  // 分配堆空間存儲metadata、refCount、value(List<Int>.node(T, List<Int>)這個case的值(是一個元組))
  %9 = alloc_box $<τ_0_0> { var (τ_0_0, List<τ_0_0>) } <Int> // users: %15, %10
  // 取出%9(類似對象)里面value的地址 *(Int, List<Int>)
  %10 = project_box %9 : $<τ_0_0> { var (τ_0_0, List<τ_0_0>) } <Int>, 0 // users: %12, %11
  // 第一個元素的地址 *Int
  %11 = tuple_element_addr %10 : $*(Int, List<Int>), 0 // user: %13
  // 第二個元素的地址 *List<Int>
  %12 = tuple_element_addr %10 : $*(Int, List<Int>), 1 // user: %14
  // 將4存入元組中第一個元素的地址里
  store %6 to %11 : $*Int                         // id: %13
  // 將List<Int>.end存入元組中第二個元素的地址里
  store %8 to %12 : $*List<Int>                   // id: %14
  // 構建一個枚舉  List<Int>.node %9--->List<Int>.node(4, List<Int>.end)
  %15 = enum $List<Int>, #List.node!enumelt, %9 : $<τ_0_0> { var (τ_0_0, List<τ_0_0>) } <Int> // user: %16
  store %15 to %3 : $*List<Int>                   // id: %16
  %17 = integer_literal $Builtin.Int32, 0         // user: %18
  %18 = struct $Int32 (%17 : $Builtin.Int32)      // user: %19
  return %18 : $Int32                             // id: %19
} // end sil function 'main'

alloc_box:在空間上分配內存區域存放T類型的value,box相當于在value外面包裹了一層;project_box:取出來的是value的地址;可通過斷點看到調用了swift_allocObject

通過上面SIL分析可知:indirect關鍵字的本質就是在上分配一塊內存來存儲一個引用地址,該地址中存放的是被indirect修飾的case。

  1. indirect關鍵字修飾enum:表明整個enum類型都是以引用類型來存儲。

先看看indirect修飾enum時,其case的內存結構:case里面直接存放的是關聯值9;

下面是加indirect修飾enum時,其case的內存結構:case里面存放的是一個引用地址

  • Swift和OC枚舉混編

  • OC訪問Swift中的枚舉
  1. enum要用@objc修飾
  2. 必須將rawValue的類型聲明成Int類型(因為OC中的枚舉就是的整型值)
@objc enum Week : Int {
    case MON
    case TUE
    case WED
    case THU
    case FRI
    case STA
    case SUN
}

然后在OC-Swift.h橋接文件中,該enum就已存在:

typedef SWIFT_ENUM(NSInteger, Week, closed) {
  WeekMON = 0,
  WeekTUE = 1,
  WeekWED = 2,
  WeekTHU = 3,
  WeekFRI = 4,
  WeekSTA = 5,
  WeekSUN = 6,
};

OC文件中就可以直接使用

OC中使用Swift的enum
  1. OC訪問String類型的enum
// .swift文件中封裝String類型的enum
@objc class Week : NSObject {
    @objc enum WeekInt : Int {
        case MON, TUE, WED, THU, FRI, STA ,SUN
        
        var string : String {
            return Week.getName(weekValue: self)
        }
    }

   @objc class func getName(weekValue:WeekInt)->String {
        switch weekValue {
            case .MON: return "MON"
            case .TUE: return "TUE"
            case .WED: return "WED"
            case .THU: return "THU"
            case .FRI: return "FRI"
            case .STA: return "STA"
            case .SUN: return "SUN"
        }
    }
}
// OC-Swift.h橋接文件
enum WeekInt : NSInteger;
@class NSString;

SWIFT_CLASS("_TtC8YYOCTest4Week")
@interface Week : NSObject
+ (NSString * _Nonnull)getNameWithWeekValue:(enum WeekInt)weekValue SWIFT_WARN_UNUSED_RESULT;
- (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
@end

typedef SWIFT_ENUM(NSInteger, WeekInt, closed) {
  WeekIntMON = 0,
  WeekIntTUE = 1,
  WeekIntWED = 2,
  WeekIntTHU = 3,
  WeekIntFRI = 4,
  WeekIntSTA = 5,
  WeekIntSUN = 6,
};
// OC中調用
NSString *weekStr = [Week getNameWithWeekValue:WeekIntFRI];
        NSLog(@"%@", weekStr); // FRI
// Swift中調用
var weekStr = Week.WeekInt.STA.string
print(weekStr) //STA
  • Swift訪問OC中的枚舉
    OC中的枚舉會被自動轉換成Swift的enum。

1.typedef NS_ENUM方式聲明的枚舉

//OC .h文件中定義的枚舉
typedef NS_ENUM(NSInteger, YYSTATE){
    Invalid = -1,
    Failed,
    Success
};

// 自動轉換成Swift的枚舉:(在系統自動生成的Swift文件中)
public enum YYSTATE : Int {

    
    case Invalid = -1

    case Failed = 0

    case Success = 1
}

// .swift文件中使用enum:
var state = YYSTATE.Success
print(state.rawValue) // 1

//轉換后的enum的大小與步長:
print(MemoryLayout<YYSTATE>.size) //8
print(MemoryLayout<YYSTATE>.stride)  //8
查看系統生成的Swfit文件
  1. NS_ENUM方式聲明的枚舉
// OC .h文件中定義枚舉
NS_ENUM(NSInteger, YYSTATE){
    Invalid = -1,
    Failed,
    Success
};

//自動轉換后的枚舉:
public var YYSTATE: YYSTATE

public enum YYSTATE : Int {

    
    case Invalid = -1

    case Failed = 0

    case Success = 1
}

// .swift中使用枚舉:
var state = YYSTATE.Success
print(state.rawValue) // 1

//轉換后的enum的大小與步長:
print(MemoryLayout<YYSTATE>.size) //8
print(MemoryLayout<YYSTATE>.stride)  //8
  1. typedef enum方式聲明的枚舉
// .h中定義枚舉
typedef enum {
    YYSTATEInvalid = -1,
    YYSTATEFailed,
    YYSTATESuccess
}YYSTATE;

//自動轉換后的枚舉:
public struct YYSTATE : Equatable, RawRepresentable {

    public init(_ rawValue: Int32)

    public init(rawValue: Int32)

    public var rawValue: Int32
}

//.swift中使用枚舉:
var state = YYSTATESuccess
print(state.rawValue) //1

//轉換后的enum的大小與步長:
print(MemoryLayout<YYSTATE>.size) //4
print(MemoryLayout<YYSTATE>.stride)  //4
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,646評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,595評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,560評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,035評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,814評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,224評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,301評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,444評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,988評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,804評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,998評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,544評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,237評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,665評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,927評論 1 287
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,706評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,993評論 2 374

推薦閱讀更多精彩內容

  • 前言 本篇文章將講述Swift中很常用的也很重要的一個知識點 ?? Enum枚舉。首先會介紹與OC中枚舉的差別,接著...
    深圳_你要的昵稱閱讀 2,511評論 0 5
  • Swift 枚舉(enum)詳解 [TOC] 本文將介紹Swift中枚舉的一些用法和其底層原理的一些探索,以及探索...
    just東東閱讀 16,550評論 6 22
  • 枚舉的遍歷 合成枚舉 allCases Swift4.2引入 protocol CaseIterable,它被用于...
    呂建雄閱讀 1,079評論 0 1
  • C語言的枚舉 C語言的枚舉寫法 我們通過枚舉表示一周的七天 c語言中,枚舉的第一個成員默認是為0,后面的枚舉值一次...
    浪的出名閱讀 405評論 0 1
  • C語言枚舉 一周七天可以寫成 第?個枚舉成員的默認值為整型的 0,后?的枚舉值依次類推,如果我們想更改,只需要這樣...
    Mjs閱讀 244評論 0 1