Swift中是存在和OC一樣的懶加載機制的,在程序設計中,我們經常會使用 懶加載
,顧名思義,就是用到的時候再開辟空間
懶加載
- 格式:
lazy var 變量: 類型 = { 創建變量代碼 }()
- 懶加載的寫法本質上是定義並執行一個閉包
// 含義: 當dataList被使用到時, 就會執行等號后面的閉包 // 所以等號后面的閉包的()是必須寫的, 如果不寫就會報錯 // 注意點: 如果寫懶加載, 那么修飾符必須用var lazy var dataList:[String] = { print("我被加載了") return ["lnj", "lmj", "zs"] }()
lazy var satatuses: [String] = self.loadStatus() func loadStatus() -> [String] { print("我被加載了") return ["lnj", "lmj", "zs"] }
// 懶加載
private lazy var inputeTextField: UITextField = {
let inputeTextField = UITextField()
inputeTextField.keyboardType = .NumberPad
/*
8種鍵盤風格:
UIKeyboardTypeDefault, // 默認鍵盤:支持所有字符
UIKeyboardTypeASCIICapable, // 支持ASCII的默認鍵盤
UIKeyboardTypeNumbersAndPunctuation, // 標准電話鍵盤,支持+*#等符號
UIKeyboardTypeURL, // URL鍵盤,有.com按鈕;只支持URL字符
UIKeyboardTypeNumberPad, //數字鍵盤
UIKeyboardTypePhonePad, // 電話鍵盤
UIKeyboardTypeNamePhonePad, // 電話鍵盤,也支持輸入人名字
UIKeyboardTypeEmailAddress, // 用於輸入電子郵件地址的鍵盤
*/
inputeTextField.delegate = self
inputeTextField.hidden = true
return inputeTextField
}()
我們在OC中一般是這樣實現懶加載初始化的:
1: @property (nonatomic, strong) NSMutableArray *players;
2:
3: - (NSMutableArray *)players {
4: if (!_players) {
5: _players = [[NSMutableArray alloc] init];
6: }
7: return _players;
8: }
實際上我們可以這樣寫:
1: lazy var players: NSMutableArray = {
2: var temporaryPlayers = NSMutableArray()
3: temporaryPlayers.addObject("Mike Buss")
4: return temporaryPlayers
5: }()
比如iOS開發中的最常用控件UITableView
,實現數據源方法的時候,通常我們都會這樣寫
Objective-C
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.dataArray.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ //1.得到cell XWShopCell *cell = [XWShopCell cellWithTableView:tableView]; //2.傳遞模型 cell.wine = self.dataArray[indexPath.row]; //3.回傳cell return cell; }
上面的的代碼中
return self.dataArray.count;
其實就是利用
@property (nonatomic, strong) NSArray *dataArray;
@property
的特性,為屬性生成了get
和set
方法,而這里是調用的get
方法,但是上述代碼中return self.dataArray.count
會調用
- (NSArray *)dataArray{ return _dataArray}
這樣調用,如果成員屬性dataArray 開始沒有賦值的,那么在使用的時候,調用get方法,不重寫的話,會報錯,空指針,所以一般我們會重寫get方法
//重寫get方法 - (NSArray *)dataArray { if (nil == _dataArray){ _dataArray = [NSArray array]; } return _dataArray }
這樣寫,就防止了成員屬性為沒有賦值的情況
綜上所述,Objective-C的懶加載,其實就是調用成員屬性的get方法,初始化值,而Swift的懶加載,是和Objective-C不同的
Swift
//MARK tablview的 dataSource 代理方法 func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int{ return self.dataArray.count } func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell{ //1.得到cell let cell = XWShopCell.cellWithTableView(tableView) //2.傳遞模型 cell.wine = self.dataArray[indexPath.row] //3.回傳cell return cell }
而這句
return self.dataArray.count
在Swift
存儲屬性必須初始化,確認類型,或者用可選類型,總之要確認類型,畢竟Swfi
t是類型安全語言,所以Swift
提出了lazy
屬性,用法
//1.分析 NSArray 是一個閉包的返回值,而這是一個沒有參數的閉包 lazy var dataArray:NSArray = { [] }() //2.也可以寫成這樣 lazy var dataArray:NSArray = { return NSArray() }() //3.從plist文件加載 lazy var dataArray:Array<XWWine> = { let winePath = NSBundle.mainBundle().pathForResource("wine.plist", ofType: nil)! let winesM = NSMutableArray(contentsOfFile: winePath); var tmpArray:Array<XWWine>! = [] for tmpWineDict in winesM! { var wine:XWWine = XWWine.wineWithDict(tmpWineDict as! NSDictionary) tmpArray.append(wine) } print("我就運行一次") return tmpArray }()
上述的代碼,有點難理解,如果之前會Objective-C
的block
或者對C語言
的函數指針理解透徹的,可以看成是一個代碼塊,然后self.dataArray
的時候,就執行了代碼塊,但是重復調用,Lazy
屬性的代碼塊只會調用一次,lazy
修飾的是一個存儲屬性,而存放的是閉包,我想內部,應該進行了優化
Swift 懶加載小議
lazy var zyTableView: UITableView = { let tempTableView = UITableView (frame: self.view.bounds, style: UITableViewStyle.Plain) tempTableView.delegate = self tempTableView.dataSource = self return tempTableView }() 這是Swift中懶加載一個叫做zyTableView的變量。 我們今天就主要來說說這段代碼.
先來說一下懶加載的好處:
- 需要的時候初始化內存,對內存開銷較小,節省內部資源
- 代碼初始化放在一起,代碼塊比較好划分,方便別人和自己閱讀
再來說一下有爭議的地方,我剛才在幾個群里問懶加載效率低不低,有不同意見,有人說低,也有人說不低,我覺得懶加載效率是低的,最簡單的說法:
在你需要使用肥皂的時候,你沒有肥皂,然后去撿一個肥皂,和你需要使用肥皂的時候就有肥皂了,你覺得哪個效率高?懶加載就是現去撿肥皂呀,所以,懶夾在效率低。
再來看看Swift中懶加載的本質,引用絕影的原話:
它本質在siwft中確實是一個閉包,執行順序是這樣的,如果這個lazy修飾的變量沒值,就會執行閉包中的東西,不是每次都執行(本人補充:這也就是為什么在Swift中的懶加載沒有oc中判斷。if(xx==nil){初始化xx}的代碼段)。
在來看下一個問題,既然懶加載在Swift中是一個閉包,那么就用閉包來復寫一個懶夾在咯:
let name = { () -> String in return "..." } lazy var myName:String = self.name()
最后呢,如果懶夾在初始化失敗怎么辦?
答案:可選值。
lazy var value1:String = { return "aaa" }() lazy var value2:String? = { return nil }() lazy var value1:String 等價於 lazy var value1:String!