天天看點

Swift的閉包,枚舉,類和結構體

閉包(Closures)

使用過其他語言的應該對代碼塊并不陌生,Swift中的閉包與C,OC中的Block相似。 表示自包含的函數代碼塊,可以在代碼中傳遞和使用。 并且可以捕獲和存儲上下文的變量以及常量值,Swift會為你進行捕獲相關的記憶體操作。

上一篇文章提到的函數,也是一種特殊的閉包,具體在: 全局函數是有名字但是不會捕獲任何值的閉包。 嵌套函數是有名字且可以捕獲域内值的閉包。 閉包表達式是利用輕量級文法寫的可以捕獲上下文值的匿名閉包。

基本文法

表達式的一般文法以及簡化過程

Swift的閉包,枚舉,類和結構體

上面羅列了同一個行為的五種寫法,也标明了簡化方法适用的情景。

尾随閉包

上面那個閉包若使用尾随閉包的方式來寫,則表現為: reversed = sort(names) {$0 > $1}

通常我們會把具有多行的閉包表達式寫入尾随閉包。 例如Array的map方法可以對數組内的每一個元素調用一次閉包,傳回一個新的數組。

Swift的閉包,枚舉,類和結構體

這裡捕獲了numbers數組中的每個值并将output映射到一個新的strings數組中。

值捕獲

閉包可以在其上下文捕獲一些值,即使原域已經不存在。上面提到嵌套函數是有名字可以捕獲域内值的閉包。Swift中最簡單的閉包形式即是嵌套函數。

Swift的閉包,枚舉,類和結構體

這裡定義了一個嵌套函數makeIncrementor,裡面記錄了一個變量runningTotal,嵌套在裡面的函數可以捕獲這個值并将其持有保留住。

Swift的閉包,枚舉,類和結構體

但是如果新聲明了一個相同函數的變量/常量引用,則其runningTotal并不共享

Swift的閉包,枚舉,類和結構體

閉包是引用類型,上面聲明的常量是指向閉包内容的一個引用,而并非閉包内容本身。

枚舉

Swift的枚舉十分靈活,case中的值可以是字元串,字元,整型或者浮點型。并且可以指定任何類型的相關值存儲到枚舉成員中。 在Swift裡,枚舉是一等類型(first-class),它支援類所支援的特性(除了繼承),你可以為它定義一些函數讓其富有行為等等。

基本文法

Swift的閉包,枚舉,類和結構體

當我們已經确定了其是CompassPoint的時候,可以直接使用.Value省略枚舉名的形式指派。

switch比對

Swift的閉包,枚舉,類和結構體

相關值

前面提到過,我們可以為其指定任意類型的相關值存儲到枚舉成員中。 來看下面這個例子

Swift的閉包,枚舉,類和結構體

我們給BarCode枚舉存儲了一些相應case的相關值,并且可以利用綁定值的方式去通路它,如在switch中定義了個常量identifier來擷取Barcode中QRCode的相關值。

原始值

在Swift中,枚舉并不會像c,objective-c中的枚舉在你未聲明枚舉值的情況下隐式的指派0,1,2...隻有我們給其指派時才會猜測其值,但是也僅限于Int。 Swift為其定義了方法來通路原始值toRaw()或者通過fromRaw(value)通路其枚舉成員。

Swift的閉包,枚舉,類和結構體

由于我們的枚舉中并沒有5對應的成員,是以其為nil。但如果換為3,則是Green。

那如果枚舉成員是String呢?會不會也會猜測值?當然是不太可能了- - 編譯器會報錯

Swift的閉包,枚舉,類和結構體

非integer必須要給其指派才可以。

類與結構體

定義,執行個體聲明與屬性

Swift的閉包,枚舉,類和結構體

由于這裡并沒有設定自定義的指定構造器,是以可以直接使用預設的方式()來初始化一個執行個體。

通路設定屬性則使用點文法,不過與Ojbective--C不同的是,Swift允許對結構體的子屬性直接指派。另外一個不同則是Swift類不需要.h接口檔案。

Swift的閉包,枚舉,類和結構體

在OC中我們想修改Rect.Origin的x值經常需要賦一個新的origin給rect,而Swift中則可以直接修改了。

在Swift中結構體,枚舉和類都可以通過寫一些成員函數來為其添加行為。 構造時則稍有不同,結構體可以為其提供逐一成員構造器。

Swift的閉包,枚舉,類和結構體

這是系統自動提供的,而類則沒有提供。

值類型和引用類型

結構體,枚舉和類另外主要不同的一點是類型。 結構體和枚舉為值類型,類則是引用類型。

值類型指在指派傳遞的時候,系統會自動為其拷貝一個新值并傳遞給新聲明的變量或常量。

Swift的閉包,枚舉,類和結構體

我們注意在将hd指派給cinema後立即cinema的width進行了修改,但是再通路hd.width還是原來的值1920.說明隻是将hd的拷貝賦給了cinema而并不是hd本身。

引用類型這是将新的變量或常量指向了原來的對象,而并非拷貝對象值之後進行指派。

Swift的閉包,枚舉,類和結構體

這裡修改了frameRate,再通路原來變量的frameRate發現也發生了變化。原因在于他們都指向了同一塊堆記憶體。

在Swift中,判定引用相等引人了一個恒等符号"===",來判定是否引用同一執行個體,不引用同一執行個體則為"!=="(不等價于) 那麼"==="和"=="的不同在于哪裡呢? 等價于("===")表示兩個類類型的常量或變量引用同一個執行個體。 而"=="表示兩個執行個體的值是否相等,判定需要遵照類設計者定義的判定标準。

由于結構體是值類型,我們不使用等價于進行判斷。

類和結構體的異同和選擇

首先來看類和結構體的相同點: 定義屬性用于存儲值 定義方法用于提供功能 定義附屬腳本(subscript)用于通路值 定義構造器用于初始化值和配置 通過擴充以增加預設實作的功能 符合協定以對某類提供标準功能

不同點在于:(類) 繼承允許一個類繼承另一個類的特征 類型轉換允許在運作時檢查和解釋一個類執行個體的類型 解構器(析構過程會提到)允許一個類執行個體釋放任何其所被配置設定的資源 引用計數允許對一個類的多次使用

則我們通常在下列情況下考慮結構體: 用來封裝少量相關簡單資料值 預計資料傳遞會被拷貝而不是引用 結構體中的值類型屬性也會被拷貝 不需要繼承或被繼承特征和行為

集合類型的指派和拷貝行為

上面說到了值類型和引用類型。在Swift中,集合類型字典和數組在背景均以結構體實作,但是他們的情況稍微有些特殊。 雖然通常值類型的指派行為都是通過拷貝實作的,我們也不需要害怕過多使用記憶體而帶來的性能問題,Swift會管理所有的值拷貝以確定性能最優化。

字典的指派和拷貝行為

字典的key/value中,若其為值類型則拷貝值,引用類型則拷貝引用。

Swift的閉包,枚舉,類和結構體

數組的指派和拷貝行為

相比字典數組要複雜的多,當操作數組内容時,數組能提供接近C語言的性能,并且保證拷貝隻有在必要時發生。

那麼必要時是什麼時候呢?是改變數組長度的時候,例如調用了append(), insert(), remove()等函數,數組的拷貝才會發生,不改變時則屬于引用傳遞。

Swift的閉包,枚舉,類和結構體

有的時候我們想確定數組的唯一性,這時可以調用unshare方法使其變成唯一拷貝。強制拷貝則使用copy方法。但是copy在任何情況下都會建立新的拷貝,而unshare則會確定唯一引用。

在判定數組是否相同時我們也可以使用"==="來判定兩個數組是否共用相同的空間或者元素。

Swift的閉包,枚舉,類和結構體

因為他們都非共用空間,是以傳回都是false.

有關閉包,枚舉,結構體和類的基礎知識都講解完畢。歡迎勘誤和讨論。