Swift 3.0 筆記

這是我對 Swift 3.0 整理的筆記克饶,主要內(nèi)容來自于官方文檔抬纸,添加了一些指針的內(nèi)容在最后帮掉。該筆記由于只是我個人用于學(xué)習(xí)整理以及回顧使用弦悉,所以沒有對單項技術(shù)做太過深入的解析。如果你需要完整清晰的知識點解析蟆炊,請看官方文檔警绩。那是最好的 The Swift Programming Language (Swift 3)

基礎(chǔ)知識

  • 類型
  • 常量和變量
  • 輸出
  • 注釋
  • 分號
  • 數(shù)值型字面量
  • 類型別名
  • 元組
  • 可選類型
  • 錯誤處理

類型

Swift 基礎(chǔ)類型以及集合類型都是值類型。

  • 基礎(chǔ)類型
    • Int (Int8, Int16, Int32, Int64, UInt...)
    • Double (Float)
    • Bool
    • String (Character)
  • 集合類型
    • Array
    • Set
    • Dictionary
  • 元組 (Tuple)
    • (,)
  • 可選類型
    • nil

常量和變量

Swift 帶有類型推斷功能盅称,屬性的類型可以注明,也可以通過初始值推斷后室。

  • 常量: let <name>: <type> = <value>
  • 變量: var <name>: <type><!,? or noting> = <value>

輸出

public func print(_ items: Any..., separator: String = default, terminator: String = default)

注釋

// 單行注釋內(nèi)容
/// 帶 Xcode 代碼提示的單行注釋內(nèi)容

/*
    多行注釋內(nèi)容
 */
/**
    帶 Xcode 代碼提示的多行注釋內(nèi)容
 */

分號

Swift 不強制要求使用分號缩膝,但是也可以使用,比如在同一行內(nèi)些多條獨立語句的時候岸霹。

數(shù)值型字面量

  • 十進制數(shù)疾层,沒有前綴
  • 二進制數(shù),前綴是0b
  • 八進制數(shù)贡避,前綴是0o
  • 十六進制數(shù)痛黎,前綴是0x
let decimalInteger = 17
let binaryInteger = 0b10001       // 17 in binary notation
let octalInteger = 0o21           // 17 in octal notation
let hexadecimalInteger = 0x11     // 17 in hexadecimal notation

let paddedDouble = 000123.456      // 123.456
let oneMillion = 1_000_000         // 1000000
let justOverOneMillion = 1_000_000.000_000_1 // 1000000.0000001

類型別名

// typealias <New Type Name> = <Old Type Name>
typealias AudioSample = UInt16

元組 (Tuples)

把多個值組合成為一個復(fù)合值,元組內(nèi)部的值可以是任意類型刮吧,不要求是相同類型湖饱。

let http404Error = (404, "Not Found")
// http404Error 的類型是 (Int, String),值是 (404, "Not Found")

let (statusCode, statusMessage) = http404Error
print("The status code is \(statusCode)")
// 輸出 "The status code is 404"
print("The status message is \(statusMessage)")
// 輸出 "The status message is Not Found"

let (justTheStatusCode, _) = http404Error
print("The status code is \(justTheStatusCode)")
// 輸出 "The status code is 404"

print("The status code is \(http404Error.0)")
// 輸出 "The status code is 404"
print("The status message is \(http404Error.1)")
// 輸出 "The status message is Not Found"

let http200Status = (statusCode: 200, description: "OK")

print("The status code is \(http200Status.statusCode)")
// 輸出 "The status code is 200"
print("The status message is \(http200Status.description)")
// 輸出 "The status message is OK"

可選類型 (optional)

使用 ? 和 ! 來表示可選類型杀捻。? 表示使用的時候可能為 nil, ! 表示使用的時候自動解包井厌。

錯誤處理 (error handing)

// 定義可能報錯的函數(shù)
func canThrowAnError() throws {
    
}

// 調(diào)用該函數(shù)
do {
    try canThrowAnError()
    // 沒有錯誤拋出
} catch {
    // 有錯誤拋出
}

斷言

// 當(dāng) condition 為 true 則不會觸發(fā)斷言,否則就觸發(fā)致讥。
public func assert(_ condition: @autoclosure () -> Bool, _ message: @autoclosure () -> String = default, file: StaticString = #file, line: UInt = #line)


運算符 (Operators)

  • 基本運算符
  • 高級運算符

基本運算符 (Basic Operators)

  • 賦值運算符 ( = )
  • 正負號運算符 ( -, + )
  • 算術(shù)運算符 ( +, -, *, /, % )
  • 組合運算符 ( +=, -=, *=, /=, %= )
  • 三元運算符 ( <條件> ? <true 返回值> : <false 返回值> )
  • 比較運算符 ( ==, !=, >, <, >=, <=, ===, !== )
  • 空值運算符 (<可選類型> ?? <假如可選類型為空時的返回值> )
  • 區(qū)間運算符 ( ..., ..< )
  • 邏輯運算符 ( !, &&, || )

Swift 中可以對浮點數(shù)進行求余運算仅仆。


高級運算符 (Advanced Operators)

  • 位運算符 ( 反:~ 與:& 或:| 異或:^ 左移:<< 右移:>>)
  • 溢出運算符: 正常情況下整數(shù)溢出 Swift 會報錯,如果想要不進行報錯垢袱,而是采取截斷處理墓拜,可以使用溢出運算符進行加減乘法運算 ( 溢出加法:&+ 溢出減法:&- 溢出乘法:&* )
  • 優(yōu)先級和結(jié)合性: 蘋果官方文檔 Swift Standard Library Operators
  • 運算符函數(shù): 與普通函數(shù)的差別在于函數(shù)名換成了運算符而且只有一到兩個參數(shù)。
  • 自定義運算符:
    • 自定義運算符可定義在全局请契,或類型當(dāng)中咳榜,當(dāng)定義在類型當(dāng)中時必須使用該類型作為參數(shù)之一夏醉。
    • 自定義運算符有 ( prefix:前綴 infix:中綴 postfix:后綴 )
    • 自定義默認優(yōu)先級會比 Ternary 分組要高 (所以是 Logical disjunction 分組?)
// 位運算符
    // 按位反運算 ( 0 1 交換 )
    let bits: UInt8 =  0b00001111
    ~bits           // 0b11110000
    
    // 按位與運算 ( 都是 1 才為 1 )
    let bitsA: UInt8 =  0b11111100
    let bitsB: UInt8 =  0b00111111
    bitsA & bitsB    // 0b00111100
    
    // 按位或運算 ( 有一個 1 則為 1)
    let bitsA: UInt8 =  0b10110010
    let bitsB: UInt8 =  0b01011110
    bitsA | bitsB    // 0b11111110
    
    // 按位異或運算符 ( 只有 1 個是 1 時為 1 )
    let bitsA: UInt8 =  0b00010100
    let bitsB: UInt8 =  0b00000101
    bitsA ^ bitsB    // 0b00010001
    
    // 按位左移、右移運算符
    let bits: UInt8 = 4 // 00000100
    bits << 1           // 00001000
    bits << 2           // 00010000
    bits << 5           // 10000000
    bits << 6           // 00000000
    bits >> 2           // 00000001
    
// 自定義運算符以及運算符函數(shù)
    <prefix / infix / postfix> operator <運算符>: <優(yōu)先級贿衍,或為空則默認級別>
    static func <運算符>(left: <Type>, right: <Type>) -> <Type> {
        ...
    }
    
    struct Vector2D {
        var x = 0.0, y = 0.0
    }
    
    extension Vector2D {
        static func + (left: Vector2D, right: Vector2D) -> Vector2D {
            return Vector2D(x: left.x + right.x, y: left.y + right.y)
        }
    }
    
    infix operator +-: AdditionPrecedence
    
    extension Vector2D {
        static func +- (left: Vector2D, right: Vector2D) -> Vector2D {
            return Vector2D(x: left.x + right.x, y: left.y - right.y)
        }
    }
    
    let firstVector = Vector2D(x: 1.0, y: 2.0)
    let secondVector = Vector2D(x: 3.0, y: 4.0)
    let plusMinusVector = firstVector +- secondVector


字符串與字符

字符串是 struct 類型

// 字符
    let <name>: Character = "!"

// 初始化
    var <name>: String = String()
    var <name>: String = "Some String \(<value>) Other String"

// 字符串常用操作
    /*
        * 運算符 ( +, += )
        * 函數(shù)操作 ( append(), insert(), remove(), removeSubrange() )
        * 獲取字符及字符數(shù)量 ( String.characters, String.characters.count )
    */

// Unicode
    /*
        * 轉(zhuǎn)義字符
            * \0(空字符)    \\(反斜線)    \t(水平制表符)
            * \n(換行符)    \r(回車符)    \"(雙引號)    \'(單引號)
        * Unicode 標(biāo)量
            * \u{任意一到八位十六進制數(shù)且可用的 Unicode 位碼}
    */

// String.Index 字符串索引
    let test = "This is a long String, and is end!"
                ^                                 ^
                test.startIndex                   test.endIndex
    // * 利用下標(biāo)訪問字符串
    test[test.startIndex]                       // T
    test[test.index(before: test.endIndex)]     // !
    test[test.index(after: test.startIndex)]    // h
    test[test.index(test.index, offsetBy: 5)]   // s
    test[test.endIndex]                         // 錯誤
    test.index(after: test.endIndex)            // 錯誤
    test[test.startIndex ..< test.index(test.startIndex, offsetBy: 6)] // This i

    // * 遍歷下標(biāo)
    for index in test.characters.indices {
        print(test[index])
    }
    // This is a long String, and is end!


集合類型

  • Arrays
  • Sets
  • Dictionaries

Swift 中集合類型都是泛型
集合類型的數(shù)據(jù)類型必須明確

Array<Element>

// 創(chuàng)建
    var <name>: [<type>] = [Type](repeating: <init value>, count: <number>)

// 訪問
    <array>[<index>]
    <array>[<Range>]

// 常用操作
    /*
        * 運算符 ( +, += )
        * 常用屬性 ( count, isEmpty )
        * 常用方法 ( append(), insert(), remove(), removeAll(), removeLast(), removeFirst() )
    */

// 遍歷
    for value in array {
        /* do some thing */
    }

    for (index, value) in array.enumerate() {
        /* do some thing */
    }

Set<Element>

集合類型必須遵守 Hashable 協(xié)議

// 創(chuàng)建
    var <name>: Set<<type>> = Set<<type>>()

// 常用操作
    /*
        * 常用屬性 ( count, isEmpty )
        * 常用方法 ( insert(), remove(), removeAll(), removeFirst(), contains() )
    */

// 遍歷
    for value in set {
        /* do some thing */
    }

    for (index, value) in set.sorted() {
        /* do some thing */
    }

// 集合操作
    var a: Set<Int> = [1,2,3,4,5]
    var b: Set<Int> = [3,4,5,6,7]
    a.intersection(b)        // [3,4,5]         相交元素
    a.symmetricDifference(b) // [1,2,6,7]       非相交元素
    a.union(b)               // [1,2,3,4,5,6,7] 所有元素
    a.subtracting(b)         // [1,2]           a 中的非相交元素

// 集合運算
    * ==                        // 是否完全一致
    * a.isSubset(of: b)         // a 中的元素 b 是否都有
    * a.isSuperset(of: b)       // b 中的元素 a 是否都有
    * a.isStrictSubset(of: b)   // a 中的元素 b 是否都有授舟,并且 a != b
    * a.isStrictSuperset(of: b) // b 中的元素 a 是否都有,并且 a != b
    * a.isDisjoint(with: b)     // a b 是否沒有交集

Dictionary<Hashable, Any>

key 必須遵守 Hashable 協(xié)議

// 創(chuàng)建
    var <name>: Dictionary<<key type>, <value type>> = Dictionary<<key type>, <value type>>()

// 訪問和修改
    <dic>[<key>] = <Any>? // 如果 Any 不為空則是新增或修改 key 值贸辈,否則就是刪除 key 值释树。

// 常用操作
    /*
        * 常用屬性 ( count, isEmpty )
        * 常用方法 ( updateValue(), remove(), removeValue(), removeAll(), contains() )
    */

// 遍歷
    for (key, value) in dic {
        /* do some thing */
    }

    for key in dic.keys.sorted() {
        /* do some thing */
    }

    for value in dic.values.sorted() {
        /* do some thing */
    }


控制流

  • 循環(huán)
  • 分支
  • 控制轉(zhuǎn)移語句

循環(huán)

// for-in

    for <value or _> in <array like 0 ..< 10, or [1,2,3]> {
        /* do some thing */
    }

// while

    while <條件> {
        /* do some thing */
    }

    repeat {
        
    } while <條件>


分支

// if

    if <條件> {
        /* do some thing */
    } else if <條件> {
        /* do some thing */
    } else {
        /* do some thing */
    }

// switch

    switch <值> {
    case <條件>:
        /* do some thing */
    case <條件>:
        /* do some thing */
    default:
        /* do some thing */
    }

    // 各種示例
        let value: Int = 10
        switch value {
        case 0: // 單一匹配
            /* do some thing */
        case 1, 2, 3: // 復(fù)合匹配
            /* do some thing */
        case 4 ..< 7: // 區(qū)間匹配
            /* do some thing */
        default:
            /* do some thing */
        }

        let tuple: (Int, Int) = (10, 10)
        switch tuple {
        case (0, 0): // 單一匹配
            /* do some thing */
        case (1, 1), (2, 2):            // 復(fù)合匹配
            /* do some thing */
        case (3 ..< 5, 4 ..< 6):        // 區(qū)間匹配
            /* do some thing */
        case (_, 7), (8, _):            // _ 匹配所有值,表示忽略
            /* do some thing */
        case (let x, 9):                // 忽略并獲取 $0 值
            /* do some thing */
        case let (x, y):                // 忽略并獲取 $0, $1 值
            /* do some thing */
        case let (x, y) where x == 7:   // 使用 where 添加限定條件
            /* do some thing */
        default: 
            /* do some thing */
        }

// guard

    guard <條件> else {
        <必須有 retrun, continue 等退出條件>
    }

    // 解包
    guard let <value> = <value>? else {
        <必須有 retrun, continue 等退出條件>
    }

控制轉(zhuǎn)移語句

// continue 跳過當(dāng)前循環(huán)中的后面部分擎淤,直接進入下一次循環(huán)

// break 跳出當(dāng)前的循環(huán)

// return 退出當(dāng)前的函數(shù)

// fallthrough switch 語句中使用奢啥,讓某個 case 可以進入下一個 case.

// throw 錯誤拋出

// 循環(huán)標(biāo)簽

    <name>: while <條件> {
        /* do some thing */
        <name2>: while <條件> {
            /* do some thing */
            break name // 直接退出 name 循環(huán)
        }
    }

// Api 檢查

    if #available(<platform name> <version>, <...>, *) {
        // statements to execute if the APIs are available
    } else {
        // fallback statements to execute if the APIs are unavailable
    }

    if #available(iOS 10, macOS 10.12, *) {
        /* iOS 使用 iOS 10 的 API, macOS 使用 macOS 10.12 的 API */
    } else {
        /* 其他版本的 Api */
    }



函數(shù)與閉包及其調(diào)用

  • 函數(shù)
  • 閉包
  • 可選鏈

函數(shù)

函數(shù)定義: func <name>(<參數(shù)外部名> <參數(shù)內(nèi)部名>: <inout> <參數(shù)類型> = <默認值> <可變參數(shù) ...>) -> <返回值類型>

函數(shù)類型: (<參數(shù)類型>...) -> <返回值參數(shù)>

嵌套函數(shù): 函數(shù)中可以定義函數(shù),該函數(shù)只有在函數(shù)內(nèi)部有效嘴拢。


閉包

閉包是自包含的代碼庫桩盲,可以在代碼中被傳遞和使用醋虏。閉包可以捕獲和存儲其所在上下文中任意的常量和變量來使用防症,所以會導(dǎo)致引用計數(shù) +1 從而有循環(huán)引用的風(fēng)險。

全局函數(shù)是一個有名字但不會捕獲任何值的閉包吠撮。嵌套函數(shù)是有名字并可以捕獲函數(shù)內(nèi)值的閉包孝冒。閉包表達式一般都是匿名閉包柬姚。

單表達式的閉包可以省略 retrun 關(guān)鍵字。

閉包內(nèi)的參數(shù)在未定義的情況下可以使用 $0 來對參數(shù)名稱進行縮寫庄涡,$0 表示第一個參數(shù)量承, $1 表示第二個參數(shù),以此類推穴店。

閉包是引用類型的值撕捍。

@noescape 表示非逃逸閉包,限定了閉包的生命周期只能存在于當(dāng)前函數(shù)當(dāng)中泣洞。

@autoclosure 表示自動閉包忧风,這種閉包不接受參數(shù),并且由返回值斜棚。用于傳遞作為參數(shù)的表達式阀蒂,并可以省略花括號。自動閉包都默認帶了 noescape 屬性弟蚀,如果想要聲明為可逃逸閉包則是 @autoclosure(escaping).

{ (<參數(shù)名>: <參數(shù)類型>) -> <返回值類型> in
    <閉包實現(xiàn)>
}

閉包在使用的時候可以有幾種不同的方式蚤霞,以 sorted 調(diào)用為例: 
    // 完整
    closures.sort(by: { (v0: Int, v1: Int) -> Bool in
        return v0 > v1
    })

    // 上下文推斷
    closures.sort(by: { v0, v1 in
        return v0 > v1
    })

    // 隱式返回值
    closures.sort(by: { $0 > $1 })

    // 運算符函數(shù)返回
    closures.sort(by: >)

    // 尾閉包
    closures.sort { $0 > $1 }

// 非逃逸閉包
    func name(@noescape closures: (Int) -> Bool) {
        if closures(10) {
            return
        }
    }

// 自動閉包
    func name(@autoclosure(escaping) closures: () -> String) {
        customerProviders.append(closures)
    }

可選鏈

if let <value> = <object>.<value>?.<function>?.<dictionary>[<key>]?.<array>[<index>] {
    /* 只要其中有 1 個 nil, 就會返回 nil, 否則會逐層解壓。*/
    /* 利用可選鏈的特性义钉,可以實現(xiàn)鏈?zhǔn)骄幊獭?*/
}


枚舉

  • 普通枚舉
  • 關(guān)聯(lián)值 (實際上等于把每個 case 都變成可以儲存值的元組類型昧绣。)
  • 原始值 (以及其隱式賦值還有初始化)
  • 遞歸枚舉 (普通枚舉并不能以自己作為值類型,但是遞歸枚舉可以捶闸,使用 indirect)
// 普通枚舉

    enum <name> {
        case <case>
        case <case>
        ...
    }

    enum <name> {
        case <value>, <value> ...
    }

    enum Type {
        case a
        case b
    }

    var type: Type = Type.a

// 關(guān)聯(lián)值

    enum <name> {
        case <case>(<type>, <type>...)
        case <case>(<type or other type> ...)
    }

    enum Type {
        case a(Int)
        case b(String)
        case c(Int, Double)
    }

    var type: Type = Type.a(10)
    var type: Type = Type.b("Test")
    var type: Type = Type.c(10, 5.0)

// 原始值

    enum <name>: <type> {
        case <case> = <value>
        case <case> = <value>
        ...
    }

    enum <name>: <type> {
        case <case> = <value>, <case>, <case> = <value>, <case>...
    }

    enum Type: Int {
        case a = 1, b, c, d = 10, e, f
    }

    var type: Type = Type.b // rawValue = 2; Type.e.rawValue = 11
    var type: Type? = Type(rawValue: 12) // Type.f

// 遞歸枚舉

    // 部分可使用遞歸
    enum <name> {
        case <case>(<type>)
        indirect case <case>(<name>)
    }
    // 全部可使用遞歸
    indirect enum <name> {
        case <case>(<type>)
        case <case>(<name>)
    }

    indirect enum Type {
        case a(Int)
        case b(Type)
    }

    indirect enum ArithmeticExpression {
        case number(Int)
        case addition(ArithmeticExpression, ArithmeticExpression)
        case multiplication(ArithmeticExpression, ArithmeticExpression)
    }

    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 let .number(value):
            return value
        case let .addition(left, right):
            return evaluate(left) + evaluate(right)
        case let .multiplication(left, right):
            return evaluate(left) * evaluate(right)
        }
    }

    print(evaluate(product))
    // return ((5) + (4)) * (2)
    // 18


類和結(jié)構(gòu)體

  • 結(jié)構(gòu)體

  • 屬性

  • 方法

  • 下標(biāo)

  • 繼承

  • 構(gòu)造過程

  • 析構(gòu)過程

  • 嵌套類型

  • 擴展

  • 類與結(jié)構(gòu)體的差異:

    • 類是引用類型夜畴,結(jié)構(gòu)體是值類型;
    • 結(jié)構(gòu)體不允許繼承;
    • 結(jié)構(gòu)體不能類型轉(zhuǎn)換;
    • 結(jié)構(gòu)體沒有析構(gòu)器;
  • 符合以下條件可以考慮使用結(jié)構(gòu)體而不是類:

    • 主要封裝少量簡單數(shù)據(jù)
    • 被傳遞或賦值的時候希望是拷貝而不是引用
    • 封裝的值也希望是拷貝而不是引用
    • 不需要繼承

可以使用 (===) 以及 (!==) 判斷兩個類是否是同一個對象拖刃。

class <name>: <super class>, <protocol> {

    /** 屬性 **/
    var <name>: <type> = <value or no>      // 存儲屬性
    lazy var <name>: <type> = <value>       // 延遲屬性
    static var <name>: <type> = <value>     // 類型屬性,靜態(tài)屬性
    let <name>: <type> = {                  // 通過閉包對值進行初始化, let var 都行
        return <value>
    }()
    var <name>: <type> {                    // 計算屬性贪绘,不存儲內(nèi)容
        get {
            /* 只讀屬性可以不寫 get {}, 直接 return */
            return <value>
        }
        set(newValue) {
            /* set 屬性可以不設(shè)置兑牡,則是只讀屬性 */
        }
    }
    var <name>: <type> = <value> {          // 添加屬性觀察器
        didSet {
            /* ... */
        }
        willSet {
            /* ... */
        }
    }

    /** 方法 **/
    func <name>(...) {                      // 實例方法

    }
    override func <father func name>(...) { // 重寫方法

    }
    class func <name>(...) {                // 類方法

    }

    /** 下標(biāo) **/
    subscript(...) -> <type> {
        get {
            return <value>
        }
        set(newValue) {
            /* ... */
        }
    }

    /** 構(gòu)造器和析構(gòu)器**/
    init(...) {
        // super.init(...)
    }
    convenience init(...) {
        /* ... */
        self.init(...)
    }
    deinit {

    }
}

結(jié)構(gòu)體

struct <name>: <protocol> {

    /** 屬性 **/
    var <name>: <type> = <value or no>      // 存儲屬性
    lazy var <name>: <type> = <value>       // 延遲屬性
    var <name>: <type> {                    // 計算屬性,不存儲內(nèi)容
        get {
            /* 只讀屬性可以不寫 get {}, 直接 return */
            return <value>
        }
        set(newValue) {
            /* set 屬性可以不設(shè)置税灌,則是只讀屬性 */
        }
    }
    var <name>: <type> = <value> {          // 添加屬性觀察器
        didSet {
            /* ... */
        }
        willSet {
            /* ... */
        }
    }
    static var <name>: <type> = <value>     // 類型屬性均函,靜態(tài)屬性


    /** 方法 **/
    func <name>(...) {

    }
    mutating func <name>(...) {

    }
    static func <name>(...) {

    }

    /** 下標(biāo) **/
    subscript(...) -> <type> {
        get {
            return <value>
        }
        set(newValue) {
            /* ... */
        }
    }

    /** 構(gòu)造器 **/
    init(...) {
        // super.init(...)
    }
}



屬性

  • 儲存屬性 let var
  • 延遲屬性 lazy
  • 計算屬性 set get
  • 屬性監(jiān)聽器 didSet willSet
  • 靜態(tài)屬性 static
  • 全局屬性默認是延遲計算的

方法

  • 實例方法 (struct 中修改到值屬性的方法需要添加 mutating)
  • 類型方法

下標(biāo)

subscript(<name>: <Type>...) -> <Type>

繼承

  • 重寫(override): 繼承之后可以使用重寫關(guān)鍵字來重寫父類的方法
    • 方法
    • 屬性
    • 屬性觀察器
    • 構(gòu)造器
  • 調(diào)用父類(super): 在重寫的方法或?qū)傩灾锌梢酝ㄟ^ super. 來調(diào)用父類的變量或函數(shù)。
  • 防止重寫(final): 子類再不能重寫它菱涤。
    • 屬性 final var
    • 方法 final func
    • 不可繼承類 final class

構(gòu)造過程

  • 儲存屬性在構(gòu)建實例的時候必須被初始化苞也,可選屬性可以被自動初始化成 nil

    • 常量屬性可以等到構(gòu)造過程進行設(shè)置
  • 不帶外部名的構(gòu)造器參數(shù) init(_ value: Int)

  • class 和 strut 都提供了默認構(gòu)造器

    • strut 構(gòu)造器中可以調(diào)用其他構(gòu)造器 self.init(...)
    • class 構(gòu)造器中可以使用父類構(gòu)造器 super.init(...)
    • convenience 便捷構(gòu)造器,在該構(gòu)造器中需要調(diào)用其他構(gòu)造器
  • init?(...) init!(...) 可失敗構(gòu)造器粘秆,在當(dāng)中返回 nil 表示失敗

    • 可以在子類中使用非可失敗構(gòu)造器重寫父類的可失敗構(gòu)造器
  • required init() 必要構(gòu)造器如迟,子類必須要重寫構(gòu)造器

  • 構(gòu)造器規(guī)則

    • 指定構(gòu)造器必須調(diào)用其父類的指定構(gòu)造器 (或默認調(diào)用的 super.init())
    • 便捷構(gòu)造器必須調(diào)用該類的其他構(gòu)造器。
  • 兩段式構(gòu)造過程中構(gòu)造流程展示:

    • 階段 1
      • 某個指定構(gòu)造器或便利構(gòu)造器被調(diào)用攻走。
      • 完成新實例內(nèi)存的分配殷勘,但此時內(nèi)存還沒有被初始化。
      • 指定構(gòu)造器確保其所在類引入的所有存儲型屬性都已賦初值昔搂。存儲型屬性所屬的內(nèi)存完成初始化劳吠。
      • 指定構(gòu)造器將調(diào)用父類的構(gòu)造器,完成父類屬性的初始化巩趁。
      • 這個調(diào)用父類構(gòu)造器的過程沿著構(gòu)造器鏈一直往上執(zhí)行,直到到達構(gòu)造器鏈的最頂部淳附。
      • 當(dāng)?shù)竭_了構(gòu)造器鏈最頂部议慰,且已確保所有實例包含的存儲型屬性都已經(jīng)賦值,這個實例的內(nèi)存被認為已經(jīng)完全初始化奴曙。此時階段 1 完成别凹。
    • 階段 2
      • 從頂部構(gòu)造器鏈一直往下,每個構(gòu)造器鏈中類的指定構(gòu)造器都有機會進一步定制實例洽糟。構(gòu)造器此時可以訪問self炉菲、修改它的屬性并調(diào)用實例方法等等。
      • 最終坤溃,任意構(gòu)造器鏈中的便利構(gòu)造器可以有機會定制實例和使用self拍霜。

析構(gòu)過程

析構(gòu)器會在實例釋放發(fā)生之前被自動調(diào)用。


嵌套類型

class / struct / enum 類型中都可以再定義新的類型薪介。

Struct A {
    enum B {
        case ab
        enum C {
            case abc
        }
    }
}
let abc = A.B.C.abc

擴展 extension

// 使用
    extension <Type> {
        ...
    }
  • 計算屬性 var <name>: <Type> { get {} set {} }
  • 構(gòu)造器 init(...) {}
  • 方法 func <name>(...) {}
  • 可變實例方法 mutating func <name>(...) {}
  • 下標(biāo) subscript(...) -> <Type> {}
  • 嵌套類型
  • 協(xié)議


自動引用計數(shù) (ARC)

  • 默認引用都是強引用
  • weak var <name>: <Type>? 使用 weak 來進行弱引用祠饺,弱應(yīng)用都是 optional 值。
  • unowned var <name>: <Type> 使用 unowned 來進行無主引用汁政,同樣是弱引用道偷,但是非 optional 值缀旁,所以在實例被釋放后,再使用會導(dǎo)致錯誤勺鸦。
  • 如果確定在使用期間肯定不會被釋放并巍,應(yīng)該用 unowned,否則使用 weak
  • 閉包捕獲默認是強引用换途,通過定義閉包的捕獲列表可設(shè)置弱引用懊渡。
var <closure>: (<type>...) -> <return type> = {
    [unowned <value>, weak <value> = self.value] (<value>: <type>...) -> <return type> in
    ...
    return ...
}

lazy var closure: (Int, String) -> String = {
    [unowned self, weak delegate = self.delegate!] (index: Int, stringToProcess: String) -> String in
    return ...
}


錯誤處理

  • defer 使用 defer 可以定義當(dāng)前代碼塊不論在什么位置退出都會調(diào)用的代碼塊。
// 使用準(zhǔn)守 Error 協(xié)議的枚舉來表示錯誤
    enum <error name>: Error {
        case <case>
    }

    enum VendingMachineError: Error {
        case invalidSelection
        case insufficientFunds(coinsNeeded: Int)
        case outOfStock
    }

// 在發(fā)生錯誤的地方拋出錯誤拋出錯誤
    throw <error>

    throw VendingMachineError.insufficientFunds(coinsNeeded: 5)

// 使用 throws 表示一個函數(shù)可能會拋出錯誤
    func <name>(...) throws -> <type>

// do-catch 處理錯誤
    do {
        try <expression>
        <無錯誤>
    } catch <error case> {
        <錯誤處理>
    } catch <error case> where <錯誤限定條件> {
        <錯誤處理>
    } catch {
        <不被前面條件捕獲的錯誤處理>
    }

    var vendingMachine = VendingMachine()
    vendingMachine.coinsDeposited = 8
    do {
        try buyFavoriteSnack(person: "Alice", vendingMachine: vendingMachine)
    } catch VendingMachineError.invalidSelection {
        print("Invalid Selection.")
    } catch VendingMachineError.outOfStock {
        print("Out of Stock.")
    } catch VendingMachineError.insufficientFunds(let coinsNeeded) {
        print("Insufficient funds. Please insert an additional \(coinsNeeded) coins.")
    }

// try? 處理怀跛,如果錯誤返回 nil
    let <value> = try? <expression>

// try! 處理距贷,禁用錯誤傳遞,如果錯誤就崩潰
    let <value> = try! <expression>
// defer
func processFile(filename: String) throws {
    if exists(filename) {
        let file = open(filename)
        defer {
            close(file)
        }
        while let line = try file.readline() {
            // Work with the file.
        }
        // close(file) is called here, at the end of the scope.
    }
}


類型轉(zhuǎn)換

  • is : 類型檢查吻谋,if <value> is <Type> {}
  • as? / as! : 轉(zhuǎn)型忠蝗,if let <name> = <value> as? <Type> {}
  • Any : 表示任意類型
  • AnyObject : 表示任意 class 類型


協(xié)議

  • 定義
    • 屬性
    • 方法
    • 構(gòu)造器
    • 下標(biāo)
  • 使用
    • class / struct 實現(xiàn)
    • 作為類型
    • 通過協(xié)議實現(xiàn)委托代理模式
    • 通過擴展來實現(xiàn)協(xié)議
    • 協(xié)議可以在集合中使用
  • 協(xié)議操作
    • 協(xié)議可以繼承一個或多個協(xié)議,并添加新內(nèi)容
    • 協(xié)議合成: 可以將多個協(xié)議進行合成作為類型
    • 通過 is 和 as 可以對協(xié)議進行一致性檢查
    • 協(xié)議擴展: 協(xié)議擴展不能擴展存儲方法漓拾,而且必須提供默認實現(xiàn)阁最。
      • 協(xié)議擴展可通過 where 語句進行限制,只有符合的部分才會有該方法骇两。
  • 專屬協(xié)議: 通過添加 class 字段表明該協(xié)議只能被 class 類型使用
  • 可選協(xié)議速种,可選協(xié)議需要添加 @objc 關(guān)鍵字,表示使用它的類都繼承自 NSObject
  • 泛型協(xié)議: 在泛型章節(jié)中的關(guān)聯(lián)類型詳細說明
// 定義低千,以下包含協(xié)議可以定義的內(nèi)容
    protocol <name> {
        var <name>: <Type> { get set }          // 定義屬性
        
        func <name>(...) -> <Type>              // 定義方法
        static func <name>(...) -> <Type>       // 定義靜態(tài)方法
        mutating func <name>(...) -> <Type>     // 定義 mutating 方法
        
        init(...)                               // 定義構(gòu)造器
        
        subscript(_: <Type>) -> <Type> { get set } // 下標(biāo)
    }

// 遵循某協(xié)議
    class <name>: <Protocol> {
        /* 實現(xiàn)協(xié)議所規(guī)定的內(nèi)容 */
    }

// 將協(xié)議作為類型
    func <name>(<name>: <Protocol>) -> <Type> {
        ...
    }

// 通過擴展實現(xiàn)協(xié)議
    extension <Class/Struct>: <Protocol> {
        /* 實現(xiàn)協(xié)議所規(guī)定的內(nèi)容 */
    }

// 繼承
    protocol <Sub Protocol>: <Protocol>, <Protocol1> ... {
        /* 定義 */
    }
    
// 合成
    func <name>(<name>: protocol<<Protocol>, <Protocol1>>) -> <Type> {
        ...
    }
    
// 一致性
    if <value> is <Protocol> { }
    if let <name> = <value> as? <Protocol> { }
    
// 可選協(xié)議及參數(shù)
    @objc protocol <Protocol> {
        @objc optional func <name>(forCount count: Int) -> Int
        @objc optional var <name>: Int { get }
    }
    
    if let <name> = <Optional Protocol>.<Optional func>?(...) { }
    
// 協(xié)議擴展
    extension <Protocol> {
        /* 不能擴展存儲屬性配阵,而且必須提供默認實現(xiàn) */
    }

// 限制條件
    extension <Protocol> where <限定條件> {
        /* 不能擴展存儲屬性,而且必須提供默認實現(xiàn)示血,只有符合限定條件的對象才會有該內(nèi)容棋傍。 */
    }
    
// 關(guān)聯(lián)類型
    protocol <Name> {
        associatedtype <Type name>
        /* ... use Type name */
    }
    class/struct <Name>: <associated Protocol> {
        typealias <Type name> = <Type>
        /* 使用 typealias 指定 Type name 為具體類型 */
    }
    class/struct <Name><Generics>: <associated Protocol> {
        /* Generics 可以就是 Type Name */
    }



泛型

  • 泛型函數(shù): 所定義的占位類型符必須在函數(shù)聲明中出現(xiàn)(參數(shù)或返回值)
  • 泛型類型
  • 擴展泛型類型: 可使用占位類型符。
  • 泛型約束
  • 關(guān)聯(lián)類型: 通常使用 associatedtype 定義泛型協(xié)議难审,然后通過實現(xiàn) typealias 來指定類型瘫拣,或使用泛型類型來指定類型
  • where 子句可以約束泛型或泛型類型
/* Generics 表示泛型類型,不加 <> 號告喊,因為泛型需要被 <> 包含 */
// 泛型函數(shù)
    func <name><Generics>(...) -> <Type> {
        ...
    }
    
    func genericsFunc<T>(input: T) -> T {
        ...
    }

// 泛型類型
    class/struct <name><Generics> {
        
    }
    
    class Stack<T> {
        var item = [T]()
    }
    
    let s = Stack<Int>()

// 泛型約束
    func <name><Generics: <Class or Protocol>>(...) {
        ...
    }
    
    func findIndex<T: Equatable>(array: [T], _ valueToFind: T) -> Int? {
        for (index, value) in array.enumerate() {
            if value == valueToFind {
                return index
            }
        }
        return nil
    }

// 關(guān)聯(lián)類型
    protocol <Name> {
        associatedtype <Type name>
        /* ... use Type name */
    }
    class/struct <Name>: <associated Protocol> {
        typealias <Type name> = <Type>
        /* 使用 typealias 指定 Type name 為具體類型 */
    }
    class/struct <Name><Generics>: <associated Protocol> {
        /* Generics 可以就是 Type Name */
    }
    
    protocol Test {
        associatedtype Item
        func append(item: Item)
    }
    
    struct TestStruct: Test {
        typealias Item = Int
        func append(item: Item) { ... }
    }
    
    class Stack<T>: Test {
        var item = [T]()
        func append(item: T) { ... }
    }
    
    let test = TestStruct()
    let stack = Stack<Int>()
    
// Where 子句
    func test<A: Test, B: Test>(a: A, b: B) -> Bool where A.Item == B.Item, A.Item: Equatable {
        /* 
            test 函數(shù)有兩個泛型 A, B
            A 遵守 Test 協(xié)議麸拄,B 遵守 Test 協(xié)議(可以是不同的協(xié)議)
            并且 (where)
            A 的 Item 類型 必須等于 B 的 Item 類型 (比如都是 Int?)
            并且 (,)
            A 的 Item 類型遵守 Equatable 協(xié)議
         */
    }


訪問控制

  • 模塊和源文件: Swift 中框架和應(yīng)用都是獨立的模塊,通過 import 導(dǎo)入黔姜。
  • 訪問級別
    • public : 其他模塊也可訪問(框架訪問級別)拢切。
    • internal : 同一模塊才可訪問(默認訪問級別)。
    • fileprivate : 當(dāng)前文件才能訪問(文件訪問級別)秆吵。
    • private : 當(dāng)前作用域內(nèi)才能訪問(內(nèi)部訪問級別)失球。
    • 不可以在實體中定義級別更高的實體。
  • 子類化以及重寫規(guī)則
    • 具有公共訪問或更低級別的類,只能在定義它的模塊中被子類化实苞。
    • 具有公共訪問或更低級別的方法豺撑,只能在定義它的模塊中被子類重寫。
    • Public 級別的類可以被它們定義的以及 import 它們的模塊子類化
    • Public 級別的方法可以被它們定義的以及 import 它們的模塊子類化
  • 單元測試 target
    • 單元測試中默認只能訪問 open 級別黔牵,但是在導(dǎo)入應(yīng)用模塊的語句前添加 @testable 則可以進行所有權(quán)限的訪問聪轿。
  • 各種類型訪問級別
    • 自定義類型: 默認 internal, 可以顯示指定
    • 子類: 不能高于父類級別。
    • 函數(shù): 如果參數(shù)及返回值中最低級別不低于當(dāng)前環(huán)境的級別猾浦,則按當(dāng)前環(huán)境級別來算陆错。否則需要顯示的指定訪問級別,不能無法編譯金赦。
    • 嵌套類型: 默認 internal 但是如果低于環(huán)境音瓷,則與環(huán)境一致。
    • 元組: 按元組中最低級別的訪問權(quán)限來算夹抗。
    • 枚舉: 枚舉成員與枚舉的訪問基本一致绳慎,無法單獨設(shè)置。而且枚舉中使用的原始值或關(guān)聯(lián)值不能低于該枚舉的訪問級別漠烧。
    • 常量/變量/屬性/下標(biāo): 不能高于他們的類型杏愤。
    • 構(gòu)造器: require 類型的構(gòu)造器必須等同所屬類型,其他的可以低于已脓。
    • 結(jié)構(gòu)體默認構(gòu)造器: 默認 internal, 如存儲屬性有低于 internal 則按最低級別算珊楼。
    • 協(xié)議: 協(xié)議的方法和屬性必須和協(xié)議保持一樣的級別。
    • 協(xié)議繼承: 不能高于原協(xié)議度液。
    • 擴展: 默認 internal, 但是不能高于原內(nèi)容厕宗。
    • 泛型: 取決于泛型類似和泛型函數(shù)本身。
    • 別名: 不能高于原類型的等級堕担。


指針

  • 申請內(nèi)容空間并初始化一個指針: 手動申請空間的指針必須手動釋放內(nèi)存媳瞪,否則會引起內(nèi)存泄露
  • 通過參數(shù)傳遞獲取指針
  • 通過 withUnsafeMutablePointer 直接訪問變量的指針
  • 通過 withMemoryRebound 函數(shù)對指針的類型進行轉(zhuǎn)換
  • 通過 UnsafeRawPointer 來獲取一個 void* 指針并轉(zhuǎn)換成其他類型的指針
  • 通過 advanced 函數(shù)來對指針進行移動
  • 使用 UnsafeBufferPointer 指針數(shù)組

注意:當(dāng)你使用指針指向某個變量的時候,ARC 環(huán)境下并不會給這個變量添加引用計數(shù)照宝,所以有可能會在你調(diào)用之前就把該變量釋放,這時候再使用指針將會出現(xiàn)不可預(yù)知的結(jié)果句葵。

// 申請內(nèi)存空間并初始化一個指針
    let <name> = UnsafeMutablePointer<Type>.allocate(capacity: Int) 
                                        // 申請內(nèi)存空間
    <Pointer>.initialize(to: <value>)   // 初始化內(nèi)存空間
    <Pointer>.pointee                   // 通過 pointee 變量可以訪問指針的內(nèi)容厕鹃,就好像 *pointer
    <Pointer>.deallocate(capacity: Int) // 釋放內(nèi)存空間
    
    let pointer = UnsafeMutablePointer<String>.allocate(capacity: 1)
    pointer.initialize(to: "Test")
    pointer.pointee // "Test"
    pointer.deallocate(capacity:1) 
    
// 通過參數(shù)傳遞獲取指針
    func method(name: UnsafePointer<Type>) { }
    method(name: &value) // 使用 & 在傳遞參數(shù)的時候傳遞 value 的指針
    
// 通過 withUnsafeMutablePointer 直接訪問變量的指針
    func withUnsafeMutablePointer<T, Result>(to arg: inout T, _ body: (UnsafeMutablePointer<T>) throws -> Result) rethrows -> Result
    
    var value: String = "Test"
    withUnsafeMutablePointer(to: &value) { $0.pointee += "OK" }
    print(value) // TestOK

// 通過 withMemoryRebound 函數(shù)對指針的類型進行轉(zhuǎn)換
    func withMemoryRebound<T, Result>(to: T.Type, capacity count: Int, _ body: (UnsafeMutablePointer<T>) throws -> Result) rethrows -> Result
    
    var addr = sockaddr()
    withUnsafeMutablePointer(to: &addr) {
        $0.withMemoryRebound(to: sockaddr_in.self, capacity: 1) {
            $0.pointee.sin_addr.s_addr = inet_addr("127.0.0.1")
        }
    }
    
// 通過 UnsafeRawPointer 來獲取一個 void* 指針并轉(zhuǎn)換成其他類型的指針
    let intP = UnsafeMutablePointer<Int>.allocate(capacity: 1)
    intP.initialize(to: 200)
    let voidP = UnsafeRawPointer(intP)
    let int32P = voidP.assumingMemoryBound(to: Int32.self)
    int32P.pointee // 200
    
// 通過 advanced 函數(shù)來對指針進行移動
    var p = UnsafeMutablePointer<Int>.allocate(capacity: 5)
    for i in 0 ..< 5 {
        p.advanced(by: i).pointee = i + 10
    }
    for i in 0 ..< 5 {
        print(p.advanced(by: i).pointee) // 10, 11, 12, 13, 14
    }
    p.deallocate(capacity: 5)
    
    * 需要注意的是,如果這里把循環(huán)的次數(shù)改成 5 以上的數(shù)字也不會崩潰乍丈。而且可以正常的進行賦值操作剂碴。但是就好像 C 中的指針一樣,你不會知道這到底會有什么影響轻专。

// 使用 UnsafeBufferPointer 指針數(shù)組
    // 使用上一個例子中的 p 指針
    var ap = UnsafeBufferPointer(start: p, count: 5)
    ap.forEach {
        print($0) // 10, 11, 12, 13, 14
    }
    
    // 數(shù)組類型本身也有方法訪問 UnsafeBufferPointer
    var a = [20,21,22,23,24]
    a.withUnsafeBufferPointer {
        $0.forEach {
            print($0) // 20, 21, 22, 23, 24
        }
    }
    
    // 事實上忆矛,可以直接把數(shù)組當(dāng)成 UnsafePointer 進行傳遞
    func method<T>(p: UnsafePointer<T>) {
        print(p.pointee)
    }
    method(p: a) // 20
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子催训,更是在濱河造成了極大的恐慌洽议,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件漫拭,死亡現(xiàn)場離奇詭異亚兄,居然都是意外死亡,警方通過查閱死者的電腦和手機采驻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門审胚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人礼旅,你說我怎么就攤上這事膳叨。” “怎么了痘系?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵菲嘴,是天一觀的道長。 經(jīng)常有香客問我碎浇,道長临谱,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任奴璃,我火速辦了婚禮悉默,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘苟穆。我一直安慰自己抄课,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布雳旅。 她就那樣靜靜地躺著跟磨,像睡著了一般。 火紅的嫁衣襯著肌膚如雪攒盈。 梳的紋絲不亂的頭發(fā)上抵拘,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天,我揣著相機與錄音型豁,去河邊找鬼僵蛛。 笑死,一個胖子當(dāng)著我的面吹牛迎变,可吹牛的內(nèi)容都是我干的充尉。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼衣形,長吁一口氣:“原來是場噩夢啊……” “哼驼侠!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤倒源,失蹤者是張志新(化名)和其女友劉穎苛预,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體相速,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡碟渺,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了突诬。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片苫拍。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖旺隙,靈堂內(nèi)的尸體忽然破棺而出绒极,到底是詐尸還是另有隱情,我是刑警寧澤蔬捷,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布垄提,位于F島的核電站,受9級特大地震影響周拐,放射性物質(zhì)發(fā)生泄漏铡俐。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一妥粟、第九天 我趴在偏房一處隱蔽的房頂上張望审丘。 院中可真熱鬧,春花似錦勾给、人聲如沸滩报。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽脓钾。三九已至,卻和暖如春桩警,著一層夾襖步出監(jiān)牢的瞬間可训,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工捶枢, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留握截,地道東北人。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓柱蟀,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蚜厉。 傳聞我的和親對象是個殘疾皇子长已,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容

  • importUIKit classViewController:UITabBarController{ enumD...
    明哥_Young閱讀 3,776評論 1 10
  • 常量與變量使用let來聲明常量,使用var來聲明變量。聲明的同時賦值的話术瓮,編譯器會自動推斷類型康聂。值永遠不會被隱式轉(zhuǎn)...
    莫_名閱讀 436評論 0 1
  • Hello Word 在屏幕上打印“Hello, world”,可以用一行代碼實現(xiàn): 你不需要為了輸入輸出或者字符...
    restkuan閱讀 3,151評論 0 5
  • 基礎(chǔ)部分(The Basics) 當(dāng)推斷浮點數(shù)的類型時胞四,Swift 總是會選擇Double而不是Float恬汁。 結(jié)合...
    gamper閱讀 1,265評論 0 7
  • 表示終于畫完了,由于手機照相自動調(diào)節(jié)色相辜伟,可能有點奇怪氓侧,希望有人能指點
    雪蝰閱讀 379評論 1 6