Swift 中的關鍵字——Lazy

語言: CN / TW / HK

theme: condensed-night-purple highlight: atelier-estuary-light


> 這是我參與11月更文挑戰的第12天,活動詳情檢視:2021最後一次更文挑戰

引言

相信大家在日常開發時,一定用過關鍵字 Lazy。那使用它有什麼好處呢?什麼時候才需要使用呢,讓我們一起來看看吧~

使用 Lazy 可以做很多事情:

  • 例項化物件時不用給它的部分或全部成員初始值
  • 呼叫之前,永遠不會執行
  • 儲存計算值並防止重複計算

宣告 Lazy

只要在成員變數前面新增一個 Lazy 關鍵字,就可以將其宣告為 lazy。惰性成員必須宣告為 var。蘋果的說法:

You must always declare a lazy property as a variable (with the var keyword), because its initial value might not be retrieved until after instance initialization completes.

必須始終將惰性屬性宣告為可變的(使用 var 關鍵字) ,因為在例項初始化完成之前,可能無法檢索其初始值

由於所有常量在初始化結束時都必須有一個值,因此有必要將惰性屬性宣告為 var,舉個🌰,程式碼中的 fullname 是一個常量,初始化時沒有賦值,就報錯了。另一個heavyComputation被宣告為 lazy,初始化時沒有賦值,就不會報錯。這個大家應該都理解。

image.png

通過把屬性宣告為 lazy,就減輕了初始化的工作。這就是懶載入了。

懶載入

另一個使用 lazy 的好處:加快初始化速度。作為開發者,我們都希望儘快能例項化我們的物件。因此,任何繁重的任務或計算,儘量避免在初始化時來做,也必須要避免。直到真正需要他們的時候,才去呼叫。讓我們來看個例子。

image.png

從上面的例子可以明顯看出,所有的計算都是在初始化 User 例項時完成的。這是因為 heavycalculation 被宣告為 let 常量,需要在初始化結束時具有具體的值。因此,它是在同一時間計算。這並不是我們想要的。

我們把 heavycalculation 宣告為 lazy,初始化時就不會計算它的值,直到第一次呼叫:

image.png


避免重複計算

我們也可以通過計算屬性達到懶載入的效果:注意下面的程式碼和上面的程式碼的區別:

image.png

從這個示例中可以明顯看出,計算屬性在初始化時也沒有被計算。

但這是否意味著計算屬性和 lazy 屬性相似呢?雖然看起來很相似,但是他們有一個非常基本的區別,這就使得 lazy 更加有用。

讓我們試試多次訪問計算屬性,看看會發生什麼。

image.png

從程式碼中發現,當我們多次訪問計算屬性ー heavycalculation 時,每次訪問都會計算一遍(這裡是兩次)。

再來看看把 heavycalculation 宣告為 lazy 時,再多次呼叫,看看會發生什麼:

image.png

這次只計算該屬性一次。這意味著,在第一次計算值之後,它的值就會被儲存下來以備下次使用,並且與使用計算屬性的情況不同,宣告為 lazy 後,不會重複計算值。

因此,根據上面的示例,我們可以很容易地確定 lazy 屬性儲存值,並且不會在每次訪問它們時進行計算。因此,節省了大量的處理器資源和時間。


使用注意事項

在理解了懶惰的工作原理之後,現在我們必須理解它的用法,並且在使用時要小心謹慎。

注意因為 lazy 屬性只計算一次,因此內部邏輯不能依賴於其他變數,尤其是那些頻繁變化的變數。這是因為,在第一次計算後,當其他的變數的值變化後,lazy 屬性的值不能同步更新,使用時就會出錯。

此外,lazy 不是執行緒安全的。這意味著當我們在不同的執行緒上訪問同一個變數時,可能會得到不同的值。蘋果的說法:

If a property marked with the lazy modifier is accessed by multiple threads simultaneously and the property has not yet been initialized, there’s no guarantee that the property will be initialized only once.

如果標記為 lazy 修飾符的屬性被多個執行緒同時訪問,而該屬性尚未初始化,則不能保證該屬性只初始化一次。

這表明,過多使用 lazy 實際上可能會產意想不到的錯誤。但有些啥時候,我們可能想懶散地做事。由於 UI 總是在主執行緒上重新整理,這使得它成為懶載入的一個很好的選項。

總結

lazy 大家都很熟悉了,但在平時開發時,也不能為了用而用,還是要根據實際情況,酌情使用。同時注意多執行緒的坑。