Swift — 面試題挑戰賽(1)
讓我們一起來討論以及研究一些 iOS 面試題目吧。
# 前言
剛好上一梯 iOS-Camp 學員差不多到了要出去面試找工作的時期,而這段時間可能就需要複習以及科普一些常會碰到的面試題目,於是工作室的 Mentor Don Chen 提議要不要大家一起過一遍 iOS 的面試題目。
我想我裡面也有許多不太清楚的知識,需要找時間來惡補這些理論(實作派QQ),所以我決定參加這一次的面試題挑戰賽。遇到會的就當複習,不會的就需要找時間再一次深入研究囉。
面試題目在下方,有興趣的朋友也可以跟我們一起過這些 iOS 的面試題。
# 本期題目:
— Swift:
- What is an in-out parameter?
- Lazy Stored Property vs Stored Property
- Fileprivate and Private access level
#What is an in-out parameter?
個人是覺得用 reference 的概念來理解 in-out 參數,蠻簡單易懂的 😎
默認情況下,函數的參數通常為常數。如果嘗試從函數體中去改變函數參數的值時會導致編譯錯誤。這意味著你無法錯誤的改變參數的值。
如果希望函數修改參數的值,並且你想要函數調用結束後這些更改依然存在,那麼請將該參數定義為輸入輸出參數(in-out parameter)。
你只能將變數作為 in-out 參數的參數傳遞。你不能傳遞常數或是文字值作為參數,因為不能修改常數跟文字值。當你將變數名稱作為參數傳遞給輸入輸出參數時,可以在變數名稱前面放置 &
符號,標示他可以由函數修改。
in-out 參數不能具有默認值,並且可變參數(variadic parameters)不能被標記為 inout。如果你用 inout 標記一個參數,這個參數不能被 var 或者 let 標記。
下面示範一個常見數字交換的範例:
可以發現當我們執行完 swapTwoInt
後, a、b 兩者的值交換了,即使它們兩者定義在該函數體外。該函數首先將 a 的值存到一個臨時的常數 temporaryA
中,接著將 b 的值賦給 a,b 接收 a 原有的值,也就是 temporaryA
。
你可以用兩個 Int
類型的變數來調用swapTwoInts
。需要注意的是,someInt
和anotherInt
在傳入swapTwoInts
函數前,都加了&
的前綴。
輸入輸出參數與函數返回值不同,上面我們的 swapTwoInts 的函數沒有定義返回類型或返回值,但是仍然修改了 a 與 b 中的值。輸入輸出是函數在其函數體外產生效果的一種方法。
其他補充:
In-out 參數的傳遞過程如下:
- 當調用該 function 時,將複製該參數的值。
- 在函數體內,該副本被修改。
- 當該 function 返回時,其副本的值將分配給原始的參數。
這個行為被稱為 copy-in copy-out 或 call by value result。例如:當計算屬性或具有 Observer 的屬性作為 in-out 參數傳遞時,其 getter
作為函數調用的一部份被調用,其setter
作為函數返回的一部分被調用。
作為優化,當參數是存儲在記憶體中實體位址的值,在函數體內部和外部使用相同的記憶體位置,其優化的行為稱為 call by reference,它滿足了所有 copy-in copy-out 的所有要求,同時也除去了複製的開銷。使用 copy-in copy-out 給定的模型編寫程式碼,而不依賴於 call-by-reference 優化,以便在有或沒有優化的情況下它都能正常運作。
想更深入了解 in-out 參數,可以查看這篇官方文件中的 In-Out Parameters
# Lazy Stored Property vs Stored Property
這邊存儲屬性的部分就不多解釋,就單純解釋 Lazy 的部分
延遲存儲屬性(Lazy Stored Property)是一個屬性,其初始值在第一次使用時之前不會計算。透過在宣告前編寫一個 lazy
修飾符來表示為延遲存儲的屬性。
你必須總是宣告延遲屬性為變數(使用 var 關鍵字),因為它的初始值可能在實例初始化完成之前無法取得。常量屬性則必須在初始化完成之前有值,因此不能宣告為延遲。
當初始值依賴於外部因素時,延遲屬性非常有用,這些外部因素的值在實例初始化完成之後才知道。當屬性的初始值需要複雜或計算成本高的設置時,延遲屬性也很有用,除非需要,否則不應執行該設置。
舉個例子來說,當你有個需要大量的計算成本的屬性,並且不一定會訪問或修改該屬性時,使用 lazy
修飾符宣告為延遲存儲屬性很有用。延遲存儲屬性只有在第一次被使用時的時候才會被初始化,之後會一直存在。
# Fileprivate and Private access level
Swift 為程式碼中的實體提供了五種不同的訪問級別。這些訪問級別與定義實體的 source file 相關,也與 source file 所屬的 module 相關。
這邊我們就只討論 file-private 跟 private 兩個訪問級別:
- File-private 訪問將實體的使用限制在其自己的 source file 中。當在整個文件中使用這些細節時,使用 file-private 訪問來隱藏特定功能的實現細節。
- Private 訪問將實體的使用限制為封閉宣告以及同一個文件中該宣告的擴展。當這些細節只有在一個宣告中使用時,使用 private 訪問來隱藏特定的實現細節。
fileprivate:宣告的source file內才可取得,若為class,可subclass和override。private:宣告的區塊內才可取得,也就是 {} 內才可取得。若為class,可subclass和override。
宣告這些訪問級別時,內部的訪問級別不能高於外部的訪問級別,例如 class
宣告被為 private
訪問級別,其內部的內容就不能被設置為 open
。
想深入了解訪問級別 Access Control 可以查看這篇官方文件。