Swift - 構造器的總結和要注意的坑以及lazy的一個使用場景

? ? ? 這段時間用Swift寫項目時候便發現它的構造函數相比OC真的是復雜了許多,加了很多的限制和條件,不過這么設計肯定有它的道理..穩定性和可選類型的加入可能是主要原因..

? ? ? 通過<Swift Programming Language>和最近項目實戰對我目前遇到的寫構造器的各種場景和對應問題做個總結..同時用代碼驗證一下書中所說的各種限制...(只討論class,struct和enum是值類型不支持繼承)

Swift Programming Language 中對"構造過程"的描述

1. 類和結構體在創建實例時,必須為所有存儲型屬性設置合適的初始值。存儲型屬性的值不能處于一個未知的狀態.

在OC中我們不需要考慮屬性的初始值是因為屬性默認值就為nil或者0...然而Swift中有了可選類型的概念它并不會這么做,對于可選類型的屬性如果不初始化值它默認為nil..但是對于非可選類型它永遠不可以為nil,我們需要手動在這個實例出現之前(構造器中或聲明時候)為它這些屬性賦初始值,以保證這個實例每一個屬性都合法..對于計算屬性因為必須實現get方法相當于也有初始值.?

注: Swift 的nil和 Objective-C 中的nil并不一樣。在 Objective-C 中,nil是一個指向不存在對象的指針。在 Swift 中,nil不是指針——它是一個確定的值,用來表示值缺失。任何類型的可選狀態都可以被設置為nil,不只是對象類型。

OC中一個int 類型的屬性沒有初始值時候默認為0...但Swift的Int屬性聲明為可選類型(Int?)它也可能是nil,表示目前沒有值.

2. 如果結構體或類的所有屬性都有默認值,同時沒有自定義的構造器,那么 Swift 會給這些結構體或類提供一個默認構造器

這一條很好理解...但是有一種情況是這個類有父類,并且父類有指定構造器...那么這個類會繼承父類的指定構造器,相當于它具有了指定構造器.這種時候雖然沒有自定義構造器,但其實Swift并不會給它默認的構造器了.

3. 類里面的所有存儲型屬性——包括所有繼承自父類的屬性——都必須在構造過程中設置初始值。

這與第1條描述的一件事情,因為子類會繼承父類的屬性,所以子類實例的屬性還是要全部就有初始值.

4.1 指定構造器必須調用其直接父類的的指定構造器

一個子類實例的屬性全都有初始值的前提除了子類定義的屬性全部賦初值當然還要給從父類繼承來的屬性賦初值..調用父類的指定構造器可以保證父類的所有屬性成功賦初值,進而根據父類鏈繼續往上調用父類的構造器來完成這個子類實例所有屬性的賦值.?

注: 詳細請看下面"類的兩段式構造"

問題:為什么限定必須是父類的指定構造器而不能是一個便利構造器呢?最終便利構造器會調用到一個指定構造器,父類的屬性還是會全部初始化..這樣規定的原因回頭再研究.

4.2 便利構造器必須調用同類中定義的其它構造器。

4.3 便利構造器必須最終導致一個指定構造器被調用。

所謂便利構造器,意思也是在屬性全部初始化的基礎上再給添加一些其它的賦值,或者是給可選類型通過參數賦值..所以4.3調用一個指定構造器是必需的了..4.2是說只能調用同類中的.看來便利構造器還是對自身類的初始方法,在便利構造器中調用super構造器方法會報錯.

對第4條,做一個驗證.

子類指定構造器必須調用父類的指定構造器


4.2,4.3 便利構造器必須調用同類中定義的其它構造器并最終調用一個指定構造器
指定構造器必須總是向上代理, 便利構造器必須總是橫向代理

所以在給一個類添加extension的時候,通常都是使用便利構造器,先調用自身的某一個指定構造器然后再這個基礎上添加某些屬性...例如給一個UIButton添加快捷創建方式:

Swift的兩段式構造過程

第一個階段,每個存儲型屬性被引入它們的類指定一個初始值。當每個存儲型屬性的初始值被確定后,第二階段開始,它給每個類一次機會,在新實例準備使用之前進一步定制它們的存儲型屬性。

這個翻譯的說實話我感覺就一個意思..就是存儲型屬性要首先有個初始值.因為其它語言的屬性都是有默認值的,swift的屬性不聲明為可選類型必須要有初始值所以加了這么一個第一階段...

第一階段:

1. 程序調用子類的某個構造器

2. 為實例分配內存, 此時實例的內存還沒有被初始化

3. 指定構造器確保子類定義的所有實例存儲屬性都已被賦初值

4. 指定構造器將調用父類的構造器, 完成父類定義的實例存儲屬性的初始化

5. 沿著調用父類構造器的構造器鏈一直往上執行, 直到到達構造器鏈的最頂部

第二階段:

1. 沿著繼承樹往下, 構造器此時可以修改實例屬性和訪問self, 甚至可以調用實例方法

2. 最后, 構造器鏈中的便利構造器都有機會定制實例和使用self

Swift 編譯器將執行 4 種有效的安全檢查,以確保兩段式構造過程能不出錯地完成:

直接看它所說的4種安全檢查吧.

安全檢查1: 指定構造器必須保證它所在類引入的所有屬性都必須先初始化完成,之后才能將其它構造任務向上代理給父類中的構造器。

為什么類中所有的屬性必須初始化完成才可以調用父類的構造任務呢?

一個對象的內存只有在其所有存儲型屬性確定之后才能完全初始化。為了滿足這一規則,指定構造器必須保證它所在類引入的屬性在它往上代理之前先完成初始化。

這個應該不是原因..因為文檔還說:一旦父類中所有屬性都有了初始值,實例的內存被認為是完全初始化..所以super之后再給子類的屬性賦值為什么不行呢? ? ? 答案?參考

安全檢查2: 指定構造器必須先向上代理調用父類構造器,然后再為繼承的屬性設置新值。如果沒這么做,指定構造器賦予的新值將被父類中的構造器所覆蓋。

事實是如果不這么做,編譯器會直接報錯.

原因就像作者所說的,這個屬性在調用super.init時肯定又被重新賦值.這一行代碼變的沒有意義

安全檢查3:便利構造器必須先調用同一個類的其他構造器, 然后才能對屬性賦值如果沒這么做,便利構造器賦予的新值將被同一類中其它指定構造器所覆蓋。

同第二條

安全檢查4: 構造器在第一階段構造完成之前,不能調用任何實例方法,不能讀取任何實例屬性的值,不能引用self作為一個值

因為第一階段完成之前內存初始化還沒有成功,顯然還沒有self這個東西..也沒有那些示例屬性呢.


在項目中遇到的一個棘手問題

需求是一個逆向傳值,,只不過這個閉包是在初始化構造函數里直接賦值..并且還要在閉包中能訪問當前實例屬性.

閉包作為構造器參數傳值同其它類型作為參數時候的語法相同..因為閉包也是一種數據類型嘛

但是想要給傳來的閉包直接進行賦值并且能在閉包中訪問屬性需要將這個帶有閉包的對象使用lazy 懶加載...如果不用lazy,此類中這個屬性在初始化的時候類實例并沒有構造完成,使用了lazy意味著這個屬性在類實例用到的時候才會初始化,所以這個時候當前類實例肯定是存在的了.才可以在閉包中使用self..

好處:很多UI控件用懶加載會緩解加載類時候的壓力.

場景:屬性本身依賴于外部因素才能初始化;可能會進行大量CPU消耗;不一定會在什么時候用到,一個事件觸發才會用到;

特別注意,項目中我在閉包中使用self.age 編譯器一直會報錯...最后找了半天原因是因為我沒有給這個懶加載的屬性設置"類型描述" 也就是冒號后面那個..這可能是編譯器的推斷出現了問題,看來以后沒事還是加上類型描述吧.

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

推薦閱讀更多精彩內容

  • 本章將會介紹 存儲屬性的初始賦值自定義構造過程默認構造器值類型的構造器代理類的繼承和構造過程可失敗構造器必要構造器...
    寒橋閱讀 778評論 0 0
  • 構造過程是使用類、結構體或枚舉類型的實例之前的準備過程。在新實例可用前必須執行這個過程,具體操作包括設置實例中每個...
    莽原奔馬668閱讀 696評論 0 3
  • 構造過程 構造過程是使用類、結構體或枚舉類型的實例之前的準備過程。在新實例可用前必須執行這個過程,具體操作包括設置...
    蠱毒_閱讀 738評論 0 2
  • 123.繼承 一個類可以從另外一個類繼承方法,屬性和其他特征。當一個類繼承另外一個類時, 繼承類叫子類, 被繼承的...
    無灃閱讀 1,415評論 2 4
  • 端午臨中夏, 時復日清長。 龍舟江竟渡, 蒲酒味芳香。 /
    噴泉閱讀 252評論 7 5