Swift 不同凡響的地方

Swift 不同凡響的地方

switch(元組)

  • 特色swift

    • 其餘語言中的switch語句只能比較離散的整形數據(字符能夠轉換成整數)
    • 可是swift中能夠比較整數、浮點數、字符、字符串、和元組數據類型,並且它能夠是離散的也可使連續的範圍
    • 並且在swift中case語句不須要顯示的添加break語句,分支語句會自動進行跳轉
    • 每一個switch語句至少有一個default語句
  • switch中比較元組數組

    • 能夠在元組中進行值綁定,來對某一個值進行判斷
    • 可使用where 語句對元組中的條件進行判斷

跳轉語句

  • break、contune、fallthrough、return

break

  • 主要用戶循環體中終止循環閉包

  • break的使用有兩種方式框架

    break	// 	沒有標籤
    break label // 添加標籤
    // break語句中標籤的使用
    label1: for var x = 0; x < 5; x++ { // 標籤1
        label2: for var y = 0; y > 0; y-- { // 標籤2
            if x == y {
            break label1 // 默認是跳出標籤2,加上標籤,能夠直接跳出到指定循環
            }
            print("(x,y) = (\(x),\(y))")
        }
    }

continue

  • continue 的使用和break相似,可使用標籤指定繼續的循環ide

    // continue語句中標籤的使用
    label1: for var x = 0; x < 5; x++ { // 標籤1
        label2: for var y = 0; y > 0; y-- { // 標籤2
            if x == y {
                continue label1 // 默認是跳出標籤2,加上標籤,能夠直接跳出到指定循環
            }
            print("(x,y) = (\(x),\(y))")
        }
    }

fallthrough

  • fallthrough是貫通語句,在swift的swiftch語句中case語句不能貫通,可是若是咱們須要設置貫通語句,可使用fallthrough語句
  • 在switch語句中case後fallthrough,會執行下一個case語句

函數

  • 參數傳遞函數

    • 外部參數名和內部參數名
    • 外部參數名能夠在調用函數時顯示出來
    func rectangle(W width:Int, H height:Int) -> Int {
    	// 	其中W\H是外部參數名,在外部調用這個方法時會顯示出來,提示這個參數是神馬意思
    	// width\height 是內部參數,在函數內部調用使用
    	return width * height
    }
    • 也可讓內部便令名變爲外部變量名,使用字符 「#」
    func rectangle(#width:Int, #height:Int) -> Int{
    	// 	其中W\H是外部參數名,在外部調用這個方法時會顯示出來,提示這個參數是神馬意思
    	// width\height 是內部參數,在函數內部調用使用
    	return width * height
    }
  • 參數默認值設計

    func rectangle(#width:Int = 100, #height:Int = 100) -> Int {
    	// 	其中W\H是外部參數名,在外部調用這個方法時會顯示出來,提示這個參數是神馬意思
    	// width\height 是內部參數,在函數內部調用使用
    	return width * height
    }
  • 可變參數代理

    func sum(numbers: Double... ) -> Double {
    	var total: Double = 0
    	for num in numbers {
    		total += num
    	}
    	return total
    }
  • 參數的引用傳遞rest

    • 在衆多數據類型中,只有類是引用傳遞,其餘的數據類型如整形、浮點型、布爾型、字符串、元組、集合、數據、枚舉、結構體都是值傳遞。
    • 若是必定要把一個值傳遞的類型的數據變爲引用傳遞模型的話,可以使用關鍵字'inout'
    func rectangle(inout width:Int, increased:Int = 1 ) {
    	width += increased
    }
    var value:Int = 10
    rectangle(&value) // 結果是11
    rectangle(&value,100) // 結果是111
  • 函數返回值code

    • 特別之處是能夠返回一個元組,表示多個值
    func rectangleArea(width:Double, increased:Double = 1 ) -> (area:Double,height:Double) //返回面積和高度
  • 函數類型

    • 函數類型包括函數參數類型和返回值類型
    • (Double, Double) -> Double //傳入寬高,計算面積
    • 這個就是函數類型,函數類型能夠做爲其餘函數的返回類型
    • 好比寫一個通用的方法來計算更多種圖形的面積,這時可使用這個函數類型做爲返回值
    • 函數類型還能夠做爲參數類型使用,能夠直接使用返回值做爲參數,而後能夠在函數內部調用這個函數
  • 函數重載

    • 和C++中函數重載相似,可是在swift中函數返回值類型外部參數名 也能夠做爲不一樣函數的判斷標準
  • 嵌套函數

    • 能夠在函數內部定義並調用函數

泛型和泛型函數

  • 泛型就是在運行時才肯定類型的一種機制,這個C++中的泛型一模一樣

  • 就是定義一個模板,使用多種場景

  • 函數參數或者返回值到運行時才能肯定

    func add(a:Int, b:Int) -> Int
    	{
    		return a + b
    	}
    	func add(a:Double, b:Double) -> Double
    	{
    		return a + b
    	}
  • 若是用泛型計算兩個數的和,能夠寫成下面這個樣

    func add<T>)(a:T, b:T) -> T {
    		return a + b
    	}
    	// 或者指定多重類型
    	func add<T,U>(a:T, b:U) -> T {
    		return a + T(b)
    	}
  • 若是比較兩個類型的話,那麼必需要遵照Comparable協議才能夠

    func isEquals<T: Comparable>(a:T, b:T) -> Bool {
    		return (a == b)
    	}

閉包

  • 閉包是自包含的匿名函數代碼塊,能夠做爲表達式、函數參數和函數返回值。

    { (參數列表) -> 返回值類型 in
    		語句組
    }

使用舉例

  • 完整版本

    {(a:Int, b:Int) -> Int in 
    		return a + b
    	}
  • 簡化版本 {a,b in return a + b }

    • 若是閉包中只有一條return語句,那麼return 語句能夠省略 {a,b in a + b }
    • 縮寫參數名稱 {$0 + $1} swift會自動推到出參數類型,$0表示第一個參數,$1表示第二個參數
    • 閉包做爲返回值,直接能夠爲變量和常量賦值
    let reslut:Int = {(a:Int, b:Int) -> Int in 
    		return a + b
    	}(10, 89)
  • 捕獲上下文中的變量和常量

    • 嵌套函數和閉包能夠訪問其所在上下文中的常量和變量,這就是捕獲值。即使是定義這些常量或變量的做用域已經不存在,嵌套函數或閉包仍然能夠在函數體內或閉包內修改或引用這些值。

swift中的面向對象

枚舉

  • swift中枚舉能夠存儲多種數據類型,並非真正的整數

    // 默認並非整形
    	enum WeekDays {		
    		case Monday
    		case Tuesday
    		case Wednesday
    		case Thursday
    		case Friday
    	}
    	// 簡寫
    		enum WeekDays {
    		case Monday, Tuesday, Wednesday, Thursday, Friday
    	}
  • 注意:在switch中使用枚舉類型時,語句中的case必須所有包含枚舉中全部成員,不能多也不能少,包括default語句。

  • 指定沒枚舉的原始值,能夠是字符、字符串、整數、浮點數等

    // 指定枚舉的原始值
    	enum WeekDays: Int {
    		case Monday = 0
    		case Tuesday
    		case Wednesday
    		case Thursday
    		case Friday
    	}
  • 原始值使用的話,要用到函數 toRaw()fromRaw()

結構體

  • swift中結構體和類很是相似,能夠定義成員變量和方法
  • 結構體不具有繼承、運行時強制類型轉換、析構函數、引用計數等
  • 除了對象是引用傳遞,其餘數據類型都是值傳遞,引用之間的比較可使用 ‘=’ 和 ‘!=’

可選類型和可選鏈

  • 「?」 和 "!"

    • 不肯定一個變量是否有值,能夠加 ?
  • 可選綁定 : 若是賦值不爲nil的話就執行if語句

    if let result: Double? = divide(100,0) {
    	print("success")
    }
    else {
    	print("failure")
    }
  • 強制拆封 : 使用 ! 來強制拆封

    let result: Double? = divide(100,0)
    	print(result!)
  • 可選鏈

    • 一些可選類型內部包含其餘可選類型,而後產生層級關係。

訪問限定

  • 訪問範圍的界定主要有:模塊和源文件
  • 訪問級別:public、internal、private
  • 可修飾類、結構體、枚舉等面向對象的類型,還能夠修飾變量、常量、下標、元組、函數、屬性等。以上這些統稱「實體」
  • 使用方式
    • public : 只要在import進所在模塊,那麼在該模塊中均可訪問
    • internal : 只能訪問本身模塊的任何internal實體,不能訪問其餘模塊中的internal實體,默認就是internal修飾符
    • private : 只能在當前源文件中訪問的實體。
  • 設計原則
    • 若是是本身在本文件內部使用,就用默認的就行。
    • 若是是開發第三方框架的話,那麼必定要設計好訪問級別,接口必定要public。其餘的能夠private

屬性和下標

一、存儲屬性

  • 存儲屬性適用於類和結構體兩種類型,包括常量屬性(let)和變量屬性(var

    • 在一個類中定義一個結構體對象屬性或者類對象屬性時就算是存儲屬性,能夠指定默認值
  • 能夠對存儲屬性進行延遲加載

  • 屬性觀察者

    • 使用在通常的存儲屬性和計算屬性上
    • willSet 在設置新值以前調用
    • didSet 在設置新值以後立刻調用
    var fullName: String {
        didSet {
             fullName = firstName + "." + secondName
        }

二、計算屬性

  • 計算屬性自己不存儲數據,只從其餘存儲屬性中得到數據。類、結構體、枚舉均可以定義計算屬性

  • 計算屬性只能使用var修飾

    var firstName: String = "Jone"
    var secondName: String = "Hu"
    // 計算屬性
    var fullName: String {
        get {
            return firstName + "." + secondName
        }
        set (newValue) {
            let names = newValue.componentsSeparatedByString(".")
            firstName = names[0]
            secondName = names[1]
        }
    }
  • 只讀計算屬性,只寫set方法便可,這是能夠省略set,直接return便可

    var firstName: String = "Jone"
    var secondName: String = "Hu"
    // 計算屬性
    var fullName: String {
       return firstName + "." + secondName
    }

三、靜態屬性

  • 能夠在類、結構體、枚舉中定義靜態屬性

四、下標

  • 一些集合類型,可使用下標訪問

    /**
    *  定義二維數組,使用下標訪問數組
    *  內部仍是一個一維數組,不過展現給外界的時一個二維訪問方式
    */
    struct DoubleArray {
        // 屬性定義
        let rows: Int
        let cols: Int
        var grid: [Int]
        
        // 構造方法
        init(rows: Int, cols: Int) {
            self.rows = rows
            self.cols = cols
            grid = Array(count: rows * cols, repeatedValue: 0) // 利用泛型建立一個數組
        }
        
        // 下標定義
        subscript(row: Int, col: Int) -> Int {
            get {
                return grid[row * col + col]
            }
            set (newValue) {
                grid[row * col + col] = newValue
            }
        }
    }
    
    // 使用二維數組
    var arr2 = DoubleArray(rows: 10, cols: 10)
    
    // 初始化二維數組
    for var i = 0; i < 10; i++ {
        for var j = 0; j < 10; j++ {
            arr2[i,j] = i * j
        }
    }
    
    // 輸出二維數組
    for var i = 0; i < 10; i++ {
        for var j = 0; j < 10; j++ {
            print("\t \(arr2[i,j])")
        }
        print("\n")
    }

方法

  • 類、結構體、枚舉中均可以定義方法
  • 這裏主要說結構體和枚舉中方法的定義
    • 默認狀況下,結構體和枚舉中的方法是不能修改屬性的
    • 若是要修改屬性的話,須要在方法以前加關鍵字 mutating ,稱之爲變異方法

靜態方法

  • 結構體和枚舉中靜態方法用static,類中靜態方法使用class

  • 一、結構體中的靜態方法

    • 不能訪問示例屬性和示例方法
    /**
    *  結構體中的靜態方法
    */
    struct Account {
        var owner: String = "Jack"
        static var interestRate: Double = 0.668
        // 靜態方法
        static func interestRateBy(amount: Double) -> Double  {
            return interestRate * amount
        }
        func messageWith(amount: Double) -> String {
            let interest  = Account.interestRateBy(amount)
            return "\(self.owner) 的利息是 \(interest)"
        }
    }
    // 調用靜態方法
    print(Account.interestRateBy(10_000.00))
    //
    var myAccount = Account()
    print(myAccount.messageWith(10_000))
  • 二、枚舉中的靜態方法

    • 不能訪問示例屬性和示例方法
    /// 枚舉中的靜態方法
    enum Account1 {
        case 中國銀行
        case 中國工商銀行
        case 中國建設銀行
        case 中國農業因銀行
        static var interestRate: Double = 0.669
        // 靜態方法定義
        static func interestBy(amount: Double) -> Double {
            return interestRate * amount
        }
    }
    // 靜態方法的調用
    print(Account1.interestBy(10_000.00))
  • 三、類中的靜態方法

    • 不能訪問示例屬性和示例方法
    /// 類中的靜態方法,使用關鍵字class
    class Account2 {
        var ower: String = "Jack"
        class func interestBy(amount: Double) -> Double {
            return 0.889 * amount
        }
    }
    // 調用靜態方法
    print(Account2.interestBy(10_000.00))

構造和析構

  • 只有類和結構體纔有構造init()和析構函數deinit
  • 在建立實例過程當中須要一些初始化操做,這個過程稱爲構造
  • 在實例最後被釋放的過程當中,須要清楚資源,這個過程稱爲析構
  • 注意: 構造器 能夠重載,沒有返回值

構造器

  • 構造器主作一些屬性的初始化操做
  • 若是不寫init方法,那麼會自動生成一個空的init構造器
  • 若是有繼承關係,要先調用父類的構造器
  • 橫向代理與向上代理
    • 橫向代理:構造器調用發生在本類內部,添加convenience關鍵字便可做爲便利構造器,便利構造器必須調用本類內部的其餘構造器
    • 向上代理:有繼承關係,就先調用父類的構造器

析構器

  • 析構器只做用於類
  • 析構器沒有返回值,沒有參數,不能重載

繼承

  • swift單繼承
  • 重寫屬性、下標以及方法
  • 重寫父類的方法使用override
  • 終止屬性或者方法的繼承可使用 final
  • 類型檢查 is as Any AnyObject
    • is 類型判斷
    • as 類型轉換
    • Any 任何類型,包括類和其餘數據類型
    • AnyObject 任何類

擴展和協議

擴展extension

  • 擴展的類型可使類、結構體、枚舉
  • 擴展能夠增長屬性和方法
  • 擴展計算屬性、方法、構造器、下標
  • 注意:擴展類的構造器的時只能增長遍歷構造器,指定構造器和析構器只能由源類型指定

協議 protocol

  • 相似C++中的純虛類
  • 能夠定義屬性和方法
  • 協議能夠繼承協議

swift內存管理

  • swift內存管理遵循ARC特性
  • 對引用類型進行引用計數,基本數據類型由系統管理

循環引用問題

  • swift中解決循環引用由兩種方式
    • 一、弱引用(weak reference
    • 二、無主引用(unowned reference)
  • 弱引用能夠沒有值,所以必須設置成可選類型
  • 無主引用適用於引用對象永遠有值

閉包中的循環引用問題

  • 閉包中的循環引用的解決方法和上面的同樣,使用弱引用和無主引用

    class Person {
        let firstName: String = "Jack"
        let secondName: String = "lu"
        /**
        *  解決閉包強循環引用
        */
        lazy var fullName: (String, String) -> String = {
            // [weak self] (firstName: String, secondName: String) -> String in
            [unowned self] (firstName: String, secondName: String) -> String in
            return firstName + secondName
        }
    }

OC與Swift

  • OC和swift能夠混合開發

  • 一、swift 調用 OC

    • 橋接文件 "<工程名>-Bridging-Header.h"
    • 在橋接文件中引入OC頭文件便可
  • 二、OC調用swift

    • 包含頭文件,這個頭文件命名樣式 "<工程名>-swift.h"
    • 在swift源文件中要把類聲明爲 @objc
    • 這時新建swift類就不須要選擇新建swift文件,而是選擇Cocoa Touch Class,而後選擇語言類型位swift