- 原文地址:Swift Lazy Initialization with Closures
- 原文做者:Bob Lee
- 譯文出自:掘金翻譯計劃
- 譯者:lsvih
- 校對者:zhangqippp,Zheaoli
親愛的讀者大家好!我是 Bob,很高興能在這篇文章中與大家相遇!如你想加入個人郵件列表,獲取更多學習 iOS 開發的文章,請點擊這兒註冊,很快就能完成的哦 :)javascript
在我剛開始學習 iOS 開發的時候,我在 YouTube 上找了一些教程。我發現這些教程有時候會用下面這種方式來建立 UI 對象:前端
let makeBox: UIView = {
let view = UIView()
return view
}()複製代碼
做爲一個初學者,我天然而然地複製並使用了這個例子。直到有一天,個人一個讀者問我:「爲何你要加上{}
呢?最後爲何要加上一對()
呢?這是一個計算屬性嗎?」我啞口無言,由於我本身也不知道答案。java
所以,我爲過去年輕的本身寫下了這份教程。說不定還能幫上其餘人的忙。react
這篇教程有一下三個目標:第一,瞭解如何像前面的代碼同樣,很是規地建立對象;第二,知道編在寫 Swfit 代碼時,何時該使用 lazy var
;第三,快加入個人郵件列表呀。android
爲了讓你能輕鬆愉快地和我一塊兒完成這篇教程,我強烈推薦你先了解下面這幾個概念。ios
在我介紹「很是規」方法以前,讓咱們先複習一下「常規」方法。在 Swift 中,若是你要建立一個按鈕,你應該會這麼作:git
// 設定尺寸
let buttonSize = CGRect(x: 0, y: 0, width: 100, height: 100)
// 建立控件
let bobButton = UIButton(frame: buttonSize)
bobButton.backgroundColor = .black
bobButton.titleLabel?.text = "Bob"
bobButton.titleLabel?.textColor = .white複製代碼
這樣作沒問題。github
假設如今你要建立另外三個按鈕,你極可能會把上面的代碼複製,而後把變量名從 bobButton
改爲 bobbyButton
。數據庫
這未免也太枯燥了吧。編程
// New Button
let bobbyButton = UIButton(frame: buttonSize)
bobbyButton.backgroundColor = .black
bobbyButton.titleLabel?.text = "Bob"
bobbyButton.titleLabel?.textColor = .white複製代碼
爲了方便,你能夠:
使用快捷鍵:ctrl-cmd-e 來完成這個工做。
若是你不想作重複的工做,你也能夠建立一個函數。
func createButton(enterTitle: String) -> UIButton {
let button = UIButton(frame: buttonSize)
button.backgroundColor = .black
button.titleLabel?.text = enterTitle
return button
}
createButton(enterTitle: "Yoyo") // 👍複製代碼
然而,在 iOS 開發中,不多會看到一堆如出一轍的按鈕。所以,這個函數須要接受更多的參數,如背景顏色、文字、圓角尺寸、陰影等等。你的函數最後可能會變成這樣:
func createButton(title: String, borderWidth: Double, backgrounColor, ...) -> Button複製代碼
可是,即便你爲這個函數加上了默認參數,上面的代碼依然不理想。這樣的設計下降了代碼的可讀性。所以,比起這個方法,咱們仍是採用上面那個」單調「的方法爲妙。
到底有沒有辦法讓咱們既不那麼枯燥,還能讓代碼更有條理呢?固然咯。咱們如今只是複習你過去的作法——是時候更上一層樓,展望你將來的作法了。
在咱們使用」很是規「方法建立 UI 組件以前,讓咱們先回答一下最開始那個讀者的問題。{}
是什麼意思,它是一個計算屬性
嗎?
固然不是,它只是一個閉包。
首先,讓我來示範一下如何用閉包來建立一個對象。咱們設計一個名爲Human
的結構:
struct Human {
init() {
print("Born 1996")
}
}複製代碼
如今,讓你看看怎麼用閉包建立對象:
let createBob = { () -> Human in
let human = Human()
return human
}
let babyBob = createBob() // "Born 1996"複製代碼
若是你不熟悉這段語法,請先中止閱讀這篇文章,去看看 Fear No Closure with Bob 充充電吧。
解釋一下,createBob
是一個類型爲 ()-> Human
的閉包。你已經經過調用 createBob()
建立好了一個 babyBob
實例。
然而,這樣作你建立了兩個常量:createBob
與 babyBob
。如何把全部的東西都放在一個聲明中呢?請看:
let bobby = { () -> Human in
let human = Human()
return human
}()複製代碼
如今,這個閉包經過在最後加上 ()
執行了本身,bobby
如今被賦值爲一個 Human
對象。乾的漂亮!
如今你已經學會了使用閉包來建立一個對象
讓咱們應用這個方法,模仿上面的例子來建立一個 UI 對象吧。
let bobView = { () -> UIView in
let view = UIView()
view.backgroundColor = .black
return view
}()複製代碼
很好,咱們還能讓它更簡潔。實際上,咱們不須要爲閉包指定類型,咱們只須要指定 bobView
實例的類型就夠了。例如:
let bobbyView: **UIView** = {
let view = UIView()
view.backgroundColor = .black
return view
}()複製代碼
Swift 可以經過關鍵字 return
推導出這個閉包的類型是 () -> UIView
。
如今看看,上面的例子已經和我以前懼怕的「很是規方式」同樣了。
咱們已經討論了直接建立對象的單調和使用構造函數帶來的問題。如今你可能會想「爲何我非得用閉包來建立?」
我不喜歡用 Storyboard,我比較喜歡複製粘貼用代碼來建立 UI 對象。實際上,在個人電腦裏有一個「代碼庫」。假設庫裏有個按鈕,代碼以下:
let myButton: UIButton = {
let button = UIButton(frame: buttonSize)
button.backgroundColor = .black
button.titleLabel?.text = "Button"
button.titleLabel?.textColor = .white
button.layer.cornerRadius =
button.layer.masksToBounds = true
return button
}()複製代碼
我只須要把它整個複製,而後把名字從 myButton
改爲 newButtom
就好了。在我用閉包以前,我得重複地把 myButton
改爲 newButtom
,甚至要改上七八遍。咱們雖然能夠用 Xcode 的快捷鍵,但爲啥不使用閉包,讓這件事更簡單呢?
因爲對象對象會本身編好組,在我看來它更加的簡潔。讓咱們對比一下:
// 使用閉包建立
let leftCornerButton: UIButton = {
let button = UIButton(frame: buttonSize)
button.backgroundColor = .black
button.titleLabel?.text = "Button"
button.titleLabel?.textColor = .white
button.layer.cornerRadius =
button.layer.masksToBounds = true
return button
}()
let rightCornerButton: UIButton = {
let button = UIButton(frame: buttonSize)
button.backgroundColor = .black
button.titleLabel?.text = "Button"
button.titleLabel?.textColor = .white
button.layer.cornerRadius =
button.layer.masksToBounds = true
return button
}()複製代碼
vs
// 手動建立
let leftCornerButton = UIButton(frame: buttonSize)
leftCornerButton.backgroundColor = .black
leftCornerButton.titleLabel?.text = "Button"
leftCornerButton.titleLabel?.textColor = .white
leftCornerButton.layer.cornerRadius =
leftCornerButton.layer.masksToBounds = true
let rightCornerButton = UIButton(frame: buttonSize)
rightCornerButton.backgroundColor = .black
rightCornerButton.titleLabel?.text = "Button"
rightCornerButton.titleLabel?.textColor = .white
rightCornerButton.layer.cornerRadius =
rightCornerButton.layer.masksToBounds = true複製代碼
儘管使用閉包建立對象要多出幾行,可是比起要在 rightCornerButton
或者 leftCornerButton
後面狂加屬性,我仍是更喜歡在 button
後面加屬性。
實際上若是按鈕的命名特別詳細時,用閉包建立對象還能夠少幾行。
恭喜你,你已經完成了咱們的第一個目標
辛苦了!如今讓咱們來看看這個教程的第二個目標吧。
你可能看過與下面相似的代碼:
class IntenseMathProblem {
lazy var complexNumber: Int = {
// 請想象這兒要耗費不少CPU資源
1 * 1
}()
}複製代碼
lazy
的做用是,讓 complexNumber
屬性只有在你試圖訪問它的時候纔會被計算。例如:
let problem = IntenseMathProblem
problem() // 此時complexNumber沒有值複製代碼
沒錯,如今 complexNumber
沒有值。然而,一旦你訪問這個屬性:
problem().complexNumber // 如今回返回1複製代碼
lazy var
常常用於數據庫排序或者從後端取數據,由於你並不想在建立對象的時候就把全部東西都計算、排序。
實際上,因爲對象太大了致使 RAM 撐不住,你的手機就會崩潰。
如下是 lazy var
的應用:
class SortManager {
lazy var sortNumberFromDatabase: [Int] = {
// 排序邏輯
return [1, 2, 3, 4]
}()
}複製代碼
class CompressionManager {
lazy var compressedImage: UIImage = {
let image = UIImage()
// 壓縮圖片的
// 邏輯
return image
}()
}複製代碼
Lazy
的一些規定lazy
和 let
一塊兒用,由於用 lazy
時沒有初值,只有當被訪問時纔會得到值。計算屬性
一塊兒用,由於在你修改任何與 lazy
的計算屬性有關的變量時,計算屬性都會被從新計算(耗費 CPU 資源)。Lazy
只能是結構或類的成員。若是你讀過個人前一篇文章《Swift 閉包和代理中的循環引用》,你就會明白這個問題。讓咱們試一試吧。建立一個名叫 BobGreet
的類,它有兩個屬性:一個是類型爲 String
的 name
,一個是類型爲 String
可是使用閉包建立的 greeting
。
class BobGreet {
var name = "Bob the Developer"
lazy var greeting: String = {
return "Hello, \(self.name)"
}()
deinit {
print("I'm gone, bruh 🙆")}
}
}複製代碼
閉包可能對 BobGuest
有強引用,讓咱們嘗試着 deallocate 它。
var bobGreet: BobGreet? = BobClass()
bobGreet?.greeting
bobClass = nil // I'm gone, bruh 🙆複製代碼
不用擔憂 [unowned self]
,閉包並無對對象存在引用。相反,它僅僅是在閉包內複製了 self
。若是你對前面的代碼聲明有疑問,能夠讀讀 Swift Capture Lists 來了解更多這方面的知識。👍
我在準備這篇教程的過程當中也學到了不少,但願你也同樣。感謝大家的熱情❤️!不過這篇文章還剩一點:個人最後一個目標。若是你但願加入個人郵件列表以得到更多有價值的信息的話,你能夠點 這裏註冊。
正如封面照片所示,我最近買了 Magic Keyboard 和 Magic Mouse。它們超級棒,幫我提高了不少的效率。你能夠在 這兒買鼠標,在 這兒買鍵盤。我纔不會由於它們的價格心疼呢。😓
我將在 6 月 1 日至 6 月 2 日 參加我有生以來的第一次討論會 @SwiftAveir, 個人朋友 Joao協助組織了此次會議,因此我很是 excited。你能夠點這兒瞭解這件事 的詳情!
函數式編程簡介 (Blog)
我最愛的 XCode 快捷鍵 (Blog )
我是一名來自首爾的 iOS 課程教師,你能夠在 Instagram 上了解我。我會常常在 Facebook Page 投稿,投稿時間通常在北京時間上午9點(Sat 8pm EST)。
掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 Android、iOS、React、前端、後端、產品、設計 等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃。