最近在寫Swift程序的時候,有個問題讓人難以理解,如下,上代碼,哥本就是這么一個直接的人,沒有什么能阻擋偶滴步伐。
lazy var tableView:UITableView = {
let tableView = UITableView()
tableView.frame = self.view.frame
tableView.dataSource = self
return tableView
}()
最后面那個()總是讓人覺得很尷尬,為啥非要加個()在后面呢?
首先,延遲計算屬性本質(zhì)上就是一個閉包,如果調(diào)用的時候這個屬性有值則直接使用,如果沒有值則觸發(fā)閉包的調(diào)用
舉個栗子,創(chuàng)建一個簡單的閉包
let myClosure = {()->String in
return "testString"
}
注意:閉包的靈活之處在于可以根據(jù)上下文推斷出自身的類型,大家不妨把()->String in 這段代碼刪掉,其實效果是一樣的。這很重要,官方有句話大致這個意思“事實上你可能不必寫出任何一個完整格式的閉包表達(dá)式”,說的就是閉包的靈活性問題
我們再聲明一個類,這個類里有一條屬性是一個閉包類型,當(dāng)然我一定會設(shè)計成()->String類型的,不然上面的閉包就沒有用處了
class Student {
var words:()->String
init(words:()->String) {
self.words = words
}
func say() {
// 這里如果我希望把學(xué)生的words打印出來,就需要調(diào)用閉包,調(diào)用閉包一定要使用括號,因為別忘了,閉包本質(zhì)就是匿名函數(shù)。
print("學(xué)生的話:\(self.words())")
}
}
現(xiàn)在創(chuàng)建一個Student實例,把myClosure作為參數(shù),再調(diào)用他的say函數(shù)
let xiaoMing = Student(words: myClosure)
xiaoMing.say()
打印結(jié)果如下
學(xué)生的話:testString
現(xiàn)在我把上面的例子稍作修改,我們使用一個字符串類型的屬性去記錄學(xué)生要說的話,而學(xué)生的話仍然有這個閉包獲取,那么上面的程序變成下面的樣子
class Student {
var words:()->String
init(words:()->String) {
self.words = words
}
// 因為閉包獲取的值編譯器無法確定獲取時間,所以不能再實例初始化一開始就賦值,所以這個message屬性必須使用lazy來聲明,并且它必須是var類型,因為它必須是可寫入的
// lazy var message:String = self.words()
// 如果上面這行代碼可以如上那樣寫,那么一定也可以如下這樣寫
lazy var message:String = {()->String in
return "closureString"
}()
func say() {
// 這里我們就可以把之前的閉包調(diào)用,改成屬性的調(diào)用了
print("學(xué)生的話:\(self.message)")
}
}
我們在實例化學(xué)生對象來觀察結(jié)果
let xiaoHong = Student(words: myClosure)
xiaoHong.say()
打印結(jié)果如下
學(xué)生的話:closureString
所以這個時候,我們想實現(xiàn)最開始的功能,可以把程序修改成如下的樣子
class Student {
func say() {
print("學(xué)生的話:\(self.message)")
}
//? ? lazy var message:String = {()->String in
//? ? ? ? return "closureString"
//? ? }()
// 由于閉包可以自動推斷自身的類型,所以可以省略成這個樣子
lazy var message:String = {
return "closureString"
}()
}
最終我們的程序變成下面的樣子了
class Student {
func say() {
print("學(xué)生的話:\(self.message)")
}
lazy var message:String = {
return "closureString"
}()
}
是不是很簡潔?所以在使用延遲計算屬性的時候,不要忘記后面的小括號哦!