結(jié)構(gòu)體和類
結(jié)構(gòu)體和類對比
* Swift 中結(jié)構(gòu)體和類有很多共同點审残。兩者都可以:
* 定義屬性用于存儲值
* 定義方法用于提供功能
* 定義下標(biāo)操作用于通過下標(biāo)語法訪問它們的值
* 定義構(gòu)造器用于設(shè)置初始值
* 通過擴展以增加默認實現(xiàn)之外的功能
* 遵循協(xié)議以提供某種標(biāo)準(zhǔn)功能
與結(jié)構(gòu)體相比,類還有如下的附加功能:
* 繼承允許一個類繼承另一個類的特征
* 類型轉(zhuǎn)換允許在運行時檢查和解釋一個類實例的類型
* 析構(gòu)器允許一個類實例釋放任何其所被分配的資源
* 引用計數(shù)允許對一個類的多次引用
? ? ? 判定兩個常量或者變量是否引用同一個類實例有時很有用斑举。為了達到這個目的搅轿,Swift 提供了兩個恒等運算符:
* 相同(===)判斷內(nèi)存地址是否相同
* 不相同(!==)
? ? ? 類支持的附加功能是以增加復(fù)雜性為代價的。作為一般準(zhǔn)則富玷,優(yōu)先使用結(jié)構(gòu)體璧坟,因為它們更容易理解,僅在適當(dāng)或必要時才使用類赎懦。實際上雀鹃,這意味著你的大多數(shù)自定義數(shù)據(jù)類型都會是結(jié)構(gòu)體和枚舉。
在結(jié)構(gòu)和類之間進行選擇
* 默認情況下使用結(jié)構(gòu)體, 結(jié)構(gòu)體的優(yōu)勢铲敛。
* 當(dāng)您需要 Objective-C 互操作性時使用類褐澎。Anyobject橋接oc会钝,必須用oc類型的接口處理數(shù)據(jù); 自定義模型繼承Objective-C framework伐蒋。
* 如果需要控制要建模的數(shù)據(jù)的標(biāo)識符使用類工三。(共享實例和本地數(shù)據(jù)庫對象)
* 使用結(jié)構(gòu)和協(xié)議對繼承和共享行為進行建模。優(yōu)先使用協(xié)議繼承先鱼,因為協(xié)議允許類俭正、結(jié)構(gòu)體和枚舉。類只能兼容其他類焙畔。
* 不需要控制標(biāo)識時使用結(jié)構(gòu)體(數(shù)據(jù)是從遠程服務(wù)器獲鹊Ф痢)
Choosing Between Structures and Classes 百度搜索之后重新看一遍,現(xiàn)在代碼量太少讀不通這篇文章宏多。特別是Use Structures When You Don't Control Identity這段文字儿惫。
值語義的特性
? ? ? 值語義特性之一? 值類型都有且僅有一個持有者;將值類型作為函數(shù)形式參數(shù)可以讓代碼天然地具有線程安全特性伸但,不可改變的東西是可以在線程之間安全共享的肾请。
? ? ? 值語義特性之一? 值類型都有且僅有一個持有者; 結(jié)構(gòu)體的隱式setter方法會自動被標(biāo)記為mutating(值語義)而改變一個結(jié)構(gòu)體變量的屬性, 相當(dāng)于重新為結(jié)構(gòu)體實例賦值 | 生成一個新的結(jié)構(gòu)體代替原來的結(jié)構(gòu)體,所以let常量的結(jié)構(gòu)體不能被改變更胖。即內(nèi)存的改變在原地進行的行為就是寫時復(fù)制铛铁,結(jié)構(gòu)體屬性被改變的一瞬間是唯一的。
? ? ? ? 值語義的特性之一? mutating(inout &) self 却妨,將隱式的self標(biāo)記inout饵逐。inout(標(biāo)記必須是可變的實參變量)將可變實參標(biāo)記為可變形參(函數(shù)形參默認不可變self),返回時將舊的值self覆蓋彪标。這種方法一般不以ed和ing結(jié)尾結(jié)尾倍权,無法對字面量和常量(不可變的形式參數(shù))結(jié)構(gòu)體進行修改。
常見錯誤:? error: cannot use mutating getter(不能在形式參數(shù)上使用var) on immutable value: ‘函數(shù)形式參數(shù)’ is a 'let' constant.
技術(shù)總結(jié): 當(dāng)你要在寫時復(fù)制的值類型中使用一些類似Foundation數(shù)據(jù)類型或者Class類型的時候需要手動復(fù)制他們的實例或者同時為它們定義一個有限制的使用接口捞烟,進而保持值語義账锹,保證值類型復(fù)制過程中不同類實例之間是不可變的(高效的深拷貝)。
寫時復(fù)制的陷阱: 避免間接訪問產(chǎn)生的不必要的復(fù)制坷襟,Swift字典和集合奸柬、其他類型(包括結(jié)構(gòu)體和Class)的下標(biāo)訪問(只有swift數(shù)組除外)會間接產(chǎn)生不必要的復(fù)制,直接訪問值類型的時候可以獲取寫時復(fù)制的優(yōu)化婴程。在不需要值語義的前提下廓奕,你可以將值類型改寫成Class類型,避免間接訪問產(chǎn)生不必要的復(fù)制 (蘋果期望將Array的地址器技術(shù)應(yīng)用到字典和集合中档叔,地址器技術(shù)未來可能會文檔化)桌粉。
構(gòu)造過程具體在playground中演示
? ? ? 構(gòu)造過程是使用類、結(jié)構(gòu)體或枚舉類型的實例之前的準(zhǔn)備過程衙四。在新實例使用前有個過程是必須的铃肯,它包括設(shè)置實例中每個存儲屬性的初始值二段式構(gòu)造過程階段一和執(zhí)行其他必須的設(shè)置二段式構(gòu)造過程階段二或構(gòu)造過程代理。
? ? ? 你要通過定義構(gòu)造器來實現(xiàn)構(gòu)造過程传蹈,它就像用來創(chuàng)建特定類型新實例的特殊方法押逼。與 Objective-C 中的構(gòu)造器不同步藕,Swift 的構(gòu)造器沒有返回值。它們的主要任務(wù)是保證某種類型的新實例在第一次使用前完成正確的初始化挑格。
默認構(gòu)造器
? ? ? 如果結(jié)構(gòu)體或類為所有屬性提供了默認值咙冗,又沒有提供任何自定義的構(gòu)造器,那么 Swift 會自動給這些結(jié)構(gòu)體或類提供一個默認構(gòu)造器漂彤。這個默認構(gòu)造器將簡單地創(chuàng)建一個所有屬性值都設(shè)置為它們默認值的實例雾消。
結(jié)構(gòu)體的逐一成員構(gòu)造器
? ? ? 結(jié)構(gòu)體如果沒有定義任何自定義構(gòu)造器,它們將自動獲得一個逐一成員構(gòu)造器(memberwise initializer)挫望。不像默認構(gòu)造器立润,即使存儲型屬性沒有默認值,結(jié)構(gòu)體也能會獲得逐一成員構(gòu)造器媳板。
? ? ? 逐一成員構(gòu)造器是用來初始化結(jié)構(gòu)體新實例里成員屬性的快捷方法范删。新實例的屬性初始值可以通過名字傳入逐一成員構(gòu)造器中。
值類型的構(gòu)造器代理代理都是指調(diào)用方法
? ? ? ? ? 構(gòu)造器可以通過調(diào)用其它構(gòu)造器來完成實例的部分構(gòu)造過程拷肌。這一過程稱為構(gòu)造器代理(調(diào)用)到旦,它能避免多個構(gòu)造器間的代碼重復(fù)。構(gòu)造器代理的實現(xiàn)規(guī)則和形式在值類型和類類型中有所不同巨缘。值類型(結(jié)構(gòu)體和枚舉類型)不支持繼承添忘,所以構(gòu)造器代理的過程相對簡單,因為它們只能代理給自己的其它構(gòu)造器若锁。類則不同搁骑,它可以繼承自其它類(請參考 繼承)。這意味著類有責(zé)任保證其所有繼承的存儲型屬性在構(gòu)造時也能正確的初始化又固。這些責(zé)任將在后續(xù)章節(jié) 類的繼承和構(gòu)造過程 中介紹仲器。
? ? ? 對于值類型,你可以使用 self.init 在自定義的構(gòu)造器中引用相同類型中的其它構(gòu)造器仰冠。并且你只能在構(gòu)造器內(nèi)部調(diào)用 self.init乏冀。
? ? ? ? 如果你為某個值類型定義了一個自定義的構(gòu)造器,你將無法訪問到默認構(gòu)造器<包括class類型洋只,也無法訪問默認構(gòu)造器>(如果是結(jié)構(gòu)體辆沦,還將無法訪問逐一成員構(gòu)造器)。此約束可避免因為使用自動(默認或逐一成員)初始化器而意外繞過更復(fù)雜的自定義初始化器的情況识虚,其中復(fù)雜初始化器提供的額外重要的設(shè)置肢扯。
類的繼承和構(gòu)造過程
? ? ? 類里面的所有存儲型屬性——包括所有繼承自父類的屬性——都必須在構(gòu)造過程中設(shè)置初始值。
? ? ? Swift 為類類型提供了兩種構(gòu)造器來確保實例中所有存儲型屬性都能獲得初始值担锤,它們被稱為指定構(gòu)造器和便利構(gòu)造器蔚晨。
指定構(gòu)造器和便利構(gòu)造器
? ? ? ? 類的指定構(gòu)造器的寫法跟值類型簡單構(gòu)造器一樣。
? ? ? ? 便利構(gòu)造器也采用相同樣式的寫法肛循,但需要在 init 關(guān)鍵字之前放置 convenience 關(guān)鍵字铭腕,并使用空格將它們倆分開银择。
? ? ? ? 1??指定構(gòu)造器是Class類型中最主要的構(gòu)造器。一個指定構(gòu)造器將初始化類中提供的所有屬性谨履,并調(diào)用合適的父類構(gòu)造器讓構(gòu)造過程沿著父類鏈繼續(xù)往上進行。許多類通過繼承了父類中的指定構(gòu)造器而滿足了這個條件 ————————? 普遍每一個類都必須至少擁有一個指定構(gòu)造器熬丧。2??只在必要的時候為類提供便利構(gòu)造器笋粟,通過使用便利構(gòu)造器來快捷調(diào)用某個指定構(gòu)造器,可以為便利構(gòu)造器的部分形參提供默認值析蝴。創(chuàng)建一個特殊用途或特定輸入值的實例害捕,能夠節(jié)省更多開發(fā)時間并讓類的構(gòu)造過程更清晰明了。
類類型的構(gòu)造器代理代理都是指調(diào)用方法
? ? 為了簡化指定構(gòu)造器和便利構(gòu)造器之間的調(diào)用關(guān)系闷畸,Swift 構(gòu)造器之間的代理調(diào)用遵循以下三條規(guī)則:
規(guī)則 1
? ? 指定構(gòu)造器必須調(diào)用其直接父類的的指定構(gòu)造器尝盼。
規(guī)則 2
? ? 便利構(gòu)造器必須調(diào)用同類中定義的其它構(gòu)造器(包括指定構(gòu)造器和其他便利構(gòu)造器)。
規(guī)則 3
? ? 便利構(gòu)造器最后必須調(diào)用指定構(gòu)造器佑菩。
一個更方便記憶的方法是:
指定構(gòu)造器必須總是向上代理
便利構(gòu)造器必須總是橫向代理
這些規(guī)則可以通過下面圖例來說明:
兩段式構(gòu)造過程
? ? ? Swift 中類的構(gòu)造過程包含兩個階段盾沫。第一個階段,類中的每個存儲型屬性賦一個初始值1殿漠。當(dāng)每個存儲型屬性的初始值被賦值后赴精,第二階段開始,它給每個類一次機會绞幌,在新實例準(zhǔn)備使用之前進一步自定義它們的存儲型屬性2蕾哟。
? ? ? 兩段式構(gòu)造過程的使用讓構(gòu)造過程更安全,同時在整個類層級結(jié)構(gòu)中給予了每個類完全的靈活性莲蜘。兩段式構(gòu)造過程可以防止屬性值在初始化之前被訪問谭确,也可以防止屬性被另外一個構(gòu)造器意外地賦予不同的值。
Swift 編譯器將執(zhí)行 4 種有效的安全檢查票渠,以確保兩段式構(gòu)造過程不出錯地完成:
安全檢查 1
????? 指定構(gòu)造器必須保證它所在類的所有屬性都必須先初始化完成逐哈,之后才能將其它構(gòu)造任務(wù)向上代理給父類中的構(gòu)造器。
? ? ? 如上所述问顷,一個對象的內(nèi)存只有在其所有存儲型屬性確定之后才能完全初始化鞠眉。階段1最后一步為了滿足這一規(guī)則,指定構(gòu)造器必須保證它所在類的屬性在它往上代理之前先完成初始化择诈。
安全檢查 2
???? ?指定構(gòu)造器必須在為繼承的屬性設(shè)置新值之前向上代理調(diào)用父類構(gòu)造器械蹋。如果沒這么做,指定構(gòu)造器賦予的新值將被父類中的構(gòu)造器所覆蓋羞芍。
安全檢查 3
????? 便利構(gòu)造器必須為任意屬性(包括所有同類中定義的)賦新值之前代理調(diào)用其它構(gòu)造器哗戈。如果沒這么做,便利構(gòu)造器賦予的新值將被該類的指定構(gòu)造器所覆蓋荷科。
安全檢查 4
???? ?構(gòu)造器在第一階段構(gòu)造完成之前唯咬,不能調(diào)用任何實例方法纱注,不能讀取任何實例屬性的值,不能引用 self 作為一個值胆胰。
? ? ? 類的實例在第一階段結(jié)束以前并不是完全有效的狞贱。只有第一階段完成后,類的實例才是有效的蜀涨,才能訪問屬性和調(diào)用方法瞎嬉。
以下是基于上述安全檢查的兩段式構(gòu)造過程展示:
階段 1
* 類的某個指定構(gòu)造器或便利構(gòu)造器被調(diào)用。
* 完成類的新實例內(nèi)存的分配厚柳,但此時內(nèi)存還沒有被初始化氧枣。
* 指定構(gòu)造器確保其所在類引入的所有存儲型屬性都已賦初值。存儲型屬性所屬的內(nèi)存完成初始化别垮。
* 指定構(gòu)造器切換到父類的構(gòu)造器便监,對其存儲屬性完成相同的任務(wù)。
* 這個過程沿著類的繼承鏈一直往上執(zhí)行碳想,直到到達繼承鏈的最頂部烧董。
* 當(dāng)?shù)竭_了繼承鏈最頂部,而且繼承鏈的最后一個類已確保所有的存儲型屬性都已經(jīng)賦值胧奔,這個實例的內(nèi)存被認為已經(jīng)完全初始化解藻。安全檢查 1此時階段 1 完成。
階段 2
* 從繼承鏈頂部往下葡盗,繼承鏈中每個類的指定構(gòu)造器都有機會進一步自定義實例螟左。構(gòu)造器此時可以訪問 self、修改它的屬性并調(diào)用實例方法等等觅够。子類可以在構(gòu)造過程修改繼承來的變量屬性胶背,但是不能修改繼承來的常量屬性。
* 最終喘先,繼承鏈中任意的便利構(gòu)造器有機會自定義實例和使用 self钳吟。
? Tip:? ? ?如果子類的構(gòu)造器沒有在階段 2 過程中做自定義操作,②并且父類有一個無參數(shù)的指定構(gòu)造器窘拯,??你可以在所有子類的存儲屬性賦值之后隱式調(diào)用(省略) super.init() 红且。
下圖展示了在假定的子類和父類之間的構(gòu)造階段 1:
以下展示了相同構(gòu)造過程的階段 2:
構(gòu)造器的繼承和重寫:
? ? ? 跟 Objective-C 中的子類不同,Swift 中的子類默認情況下不會繼承父類的構(gòu)造器涤姊。Swift 的這種機制可以防止一個父類的簡單構(gòu)造器被一個更精細的子類繼承暇番,而在用來創(chuàng)建子類時的新實例時沒有被完全初始化或被錯誤初始化。父類的構(gòu)造器僅會在安全和適當(dāng)?shù)哪承┣闆r下被繼承思喊。具體內(nèi)容請參考后續(xù)章節(jié) 構(gòu)造器的自動繼承壁酬。
? ? ? 當(dāng)你在編寫一個和父類中指定構(gòu)造器相匹配的子類構(gòu)造器時,你實際上是在重寫父類的這個指定構(gòu)造器。因此舆乔,你必須在定義子類構(gòu)造器時帶上 override 修飾符岳服。
? ? ? 當(dāng)你重寫一個父類的指定構(gòu)造器時,你總是需要寫 override 修飾符希俩,即使是為了實現(xiàn)子類的便利構(gòu)造器吊宋。相反,如果你編寫了一個和父類便利構(gòu)造器相匹配的子類構(gòu)造器颜武,由于子類不能直接調(diào)用父類的便利構(gòu)造器(每個規(guī)則都在上文 類的構(gòu)造器代理規(guī)則 有所描述)璃搜,因此,嚴格意義上來講盒刚,你的子類并未對一個父類構(gòu)造器提供重寫腺劣。最后的結(jié)果就是绿贞,你在子類中“重寫”一個父類便利構(gòu)造器時因块,不需要加 override 修飾符。
? ? ? Tip:? ? ?如果子類的構(gòu)造器沒有在階段 2 過程中做自定義操作籍铁,②并且父類有一個無參數(shù)的指定構(gòu)造器涡上,??你可以在所有子類的存儲屬性賦值之后隱式調(diào)用(省略) super.init() 。
構(gòu)造器的自動繼承:
? ? ? 如上所述拒名,子類在默認情況下不會繼承父類的構(gòu)造器吩愧。但是如果滿足特定條件,父類構(gòu)造器是可以被自動繼承的增显。事實上雁佳,這意味著對于許多常見場景你不必重寫父類的構(gòu)造器,并且可以在安全的情況下以最小的代價繼承父類的構(gòu)造器同云。
? ? ? 假設(shè)你為子類中引入的所有新屬性都提供了默認值糖权,以下 2 個規(guī)則將適用:
規(guī)則 1
????如果子類沒有定義任何指定構(gòu)造器,它將自動繼承父類所有的指定構(gòu)造器炸站。
規(guī)則 2
????如果子類提供了所有父類指定構(gòu)造器的實現(xiàn)——無論是通過規(guī)則 1 繼承過來的星澳,還是提供了自定義實現(xiàn)——它將自動繼承父類所有的便利構(gòu)造器。
即使你在子類中添加了更多的便利構(gòu)造器旱易,這兩條規(guī)則仍然適用禁偎。
注意
子類可以將父類的指定構(gòu)造器實現(xiàn)為便利構(gòu)造器來滿足規(guī)則 2。
指定構(gòu)造器和便利構(gòu)造器實踐:
下圖展示了這三個類的構(gòu)造器鏈, 代碼見playground文件:
可失敗構(gòu)造器
? ? ? 有時阀坏,定義一個構(gòu)造器可失敗的類如暖,結(jié)構(gòu)體或者枚舉是很有用的。這里所指的“失敗” 指的是忌堂,如給構(gòu)造器傳入無效的形參装处,或缺少某種所需的外部資源,又或是不滿足某種必要的條件等。其語法為在 init 關(guān)鍵字后面添加問號(init?)妄迁。
注意
? ? ? 可失敗構(gòu)造器的參數(shù)名和參數(shù)類型寝蹈,不能與其它非可失敗構(gòu)造器的參數(shù)名,及其參數(shù)類型相同登淘。
? ? ? 可失敗構(gòu)造器會創(chuàng)建一個類型為自身類型的可選類型的對象箫老。你通過 return nil 語句來表明可失敗構(gòu)造器在何種情況下應(yīng)該 “失敗”。嚴格來說黔州,構(gòu)造器都不支持返回值耍鬓,因此而不要用關(guān)鍵字 return 來表明構(gòu)造成功。
1??枚舉類型的可失敗構(gòu)造器||2??帶原始值的枚舉類型的可失敗構(gòu)造器
? ? ? 你可以通過一個帶一個或多個形參的可失敗構(gòu)造器來獲取枚舉類型中特定的枚舉成員流妻。如果提供的形參無法匹配任何枚舉成員牲蜀,則構(gòu)造失敗。
? ? ? 帶原始值的枚舉類型會自帶一個可失敗構(gòu)造器 init?(rawValue:)绅这,該可失敗構(gòu)造器有一個合適的原始值類型的 rawValue 形參涣达,選擇找到的相匹配的枚舉成員,找不到則構(gòu)造失敗证薇。
構(gòu)造失敗的傳遞
? ? ? 類度苔、結(jié)構(gòu)體、枚舉的可失敗構(gòu)造器可以橫向代理到它們自己其他的可失敗構(gòu)造器浑度。類似的寇窑,子類的可失敗構(gòu)造器也能向上代理到父類的可失敗構(gòu)造器。
? ? ? 無論是向上代理還是橫向代理箩张,如果你代理到的其他可失敗構(gòu)造器觸發(fā)構(gòu)造失敗甩骏,整個構(gòu)造過程將立即終止,接下來的任何構(gòu)造代碼不會再被執(zhí)行先慷。
注意
? ? 可失敗構(gòu)造器也可以代理到其它的不可失敗構(gòu)造器饮笛。通過這種方式,你另外需要增加一個可能的失敗狀態(tài)到現(xiàn)有的構(gòu)造過程中熟掂。
重寫一個可失敗構(gòu)造器
? ? ? 如同其它的構(gòu)造器缎浇,你可以在子類中重寫父類的可失敗構(gòu)造器「岸牵或者你也可以用子類的非可失敗構(gòu)造器重寫一個父類的可失敗構(gòu)造器素跺。這使你可以定義一個不會構(gòu)造失敗的子類,即使父類的構(gòu)造器允許構(gòu)造失敗誉券。
? ? ? 注意指厌,當(dāng)你用子類的非可失敗構(gòu)造器重寫父類的可失敗構(gòu)造器時,向上代理到父類的可失敗構(gòu)造器的唯一方式是對父類的可失敗構(gòu)造器的返回值進行強制解包踊跟。
注意
你可以用非可失敗構(gòu)造器重寫可失敗構(gòu)造器踩验,但反過來卻不行鸥诽。
init! 可失敗構(gòu)造器
? ? ? 通常來說我們通過在 init 關(guān)鍵字后添加問號的方式(init?)來定義一個可失敗構(gòu)造器,但你也可以通過在 init 后面添加感嘆號的方式來定義一個可失敗構(gòu)造器(init!)箕憾,該可失敗構(gòu)造器將會構(gòu)建一個對應(yīng)類型的隱式解包可選類型的對象牡借。
? ? ? 你可以在 init? 中代理到 init!,反之亦然袭异。你也可以用 init? 重寫 init!钠龙,反之亦然。你還可以用 init 代理到 init!御铃,不過碴里,一旦 init! 構(gòu)造失敗,則會觸發(fā)一個斷言上真。
必要構(gòu)造器
? ? ? ? required 修飾符表明所有該類的子類都必須實現(xiàn)該構(gòu)造器
? ? ? 子類重寫父類的必要構(gòu)造器時咬腋,必須添加上 required 修飾符,但不需要添加 override 修飾符睡互。
? ? ? ? 如果子類繼承的構(gòu)造器能滿足必要構(gòu)造器的要求根竿,則無須在子類中顯式提供必要構(gòu)造器的實現(xiàn)。
通過閉包或函數(shù)設(shè)置屬性的默認值
? ? ? 如果某個存儲型屬性的默認值需要一些自定義或設(shè)置湃缎,你可以使用閉包或全局函數(shù)為其提供定制的默認值犀填。每當(dāng)某個屬性所在類型的新實例被構(gòu)造時蠢壹,對應(yīng)的閉包或函數(shù)會被調(diào)用嗓违,而它們的返回值會當(dāng)做默認值賦值給這個屬性。
? ? ? 這種類型的閉包或函數(shù)通常會創(chuàng)建一個跟屬性類型相同的臨時變量图贸,然后修改它的值以滿足預(yù)期的初始狀態(tài)蹂季,最后返回這個臨時變量,作為屬性的默認值疏日。
注意
? ? ? 如果你使用閉包來初始化屬性偿洁,請記住在閉包執(zhí)行時,實例的其它部分都還沒有初始化沟优。這意味著你不能在閉包里訪問其它屬性涕滋,即使這些屬性有默認值。同樣挠阁,你也不能使用隱式的 self 屬性宾肺,或者調(diào)用任何實例方法。
析構(gòu)過程
? ? ? 析構(gòu)器只適用于類類型侵俗,當(dāng)一個類的實例被釋放之前锨用,析構(gòu)器會被立即調(diào)用。析構(gòu)器用關(guān)鍵字 deinit 來標(biāo)示隘谣,類似于構(gòu)造器要用 init 來標(biāo)示增拥。
析構(gòu)過程原理
? ? ? Swift 會自動釋放不再需要的實例以釋放資源。如 自動引用計數(shù) 章節(jié)中所講述,Swift 通過自動引用計數(shù)(ARC) 處理實例的內(nèi)存管理掌栅。通常當(dāng)你的實例被釋放時不需要手動地去清理秩仆。但是,當(dāng)使用自己的資源時猾封,你可能需要進行一些額外的清理逗概。例如,如果創(chuàng)建了一個自定義的類來打開一個文件忘衍,并寫入一些數(shù)據(jù)逾苫,你可能需要在類實例被釋放之前手動去關(guān)閉該文件。
? ? ? 在類的定義中枚钓,每個類最多只能有一個析構(gòu)器铅搓,而且析構(gòu)器不帶任何參數(shù)和圓括號
? ? ? 析構(gòu)器是在實例釋放發(fā)生前被自動調(diào)用的。你不能主動調(diào)用析構(gòu)器搀捷。子類繼承了父類的析構(gòu)器星掰,并且在子類析構(gòu)器實現(xiàn)的最后,父類的析構(gòu)器會被自動調(diào)用嫩舟。即使子類沒有提供自己的析構(gòu)器氢烘,父類的析構(gòu)器也同樣會被調(diào)用。
? ? ? 因為直到實例的析構(gòu)器被調(diào)用后,實例才會被釋放胚嘲,所以析構(gòu)器可以訪問實例的所有屬性仰挣,并且可以根據(jù)那些屬性可以修改它的行為(比如查找一個需要被關(guān)閉的文件)。