閉包
閉包的介紹
- 閉包和OC中的block非常相似
- OC中的block是匿名的函數(shù)
- Swift中的閉包是一個(gè)特殊的函數(shù)
- block和閉包都經(jīng)常用于回調(diào)
- 注意:閉包和block一樣,第一次使用時(shí)可能不習(xí)慣它的語(yǔ)法,可以先按照使用簡(jiǎn)單的閉包,隨著學(xué)習(xí)的深入,慢慢掌握其靈活的運(yùn)用方法.
閉包的使用
block的用法回顧
- 定義網(wǎng)絡(luò)請(qǐng)求的類
@interface HttpTool : NSObject
- (void)loadRequest:(void (^)())callBackBlock;
@end
@implementation HttpTool
- (void)loadRequest:(void (^)())callBackBlock
{
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"加載網(wǎng)絡(luò)數(shù)據(jù):%@", [NSThread currentThread]);
dispatch_async(dispatch_get_main_queue(), ^{
callBackBlock();
});
});
}
@end
- 進(jìn)行網(wǎng)絡(luò)請(qǐng)求,請(qǐng)求到數(shù)據(jù)后利用block進(jìn)行回調(diào)
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[self.httpTool loadRequest:^{
NSLog(@"主線程中,將數(shù)據(jù)回調(diào).%@", [NSThread currentThread]);
}];
}
- block寫(xiě)法總結(jié):
block的寫(xiě)法:
類型:
返回值(^block的名稱)(block的參數(shù))
值:
^(參數(shù)列表) {
// 執(zhí)行的代碼
};
使用閉包代替block
- 定義網(wǎng)絡(luò)請(qǐng)求的類
class HttpTools: NSObject {
func requestData(finishedCallback : @escaping (_ jsonData : String, _ age : Int) -> ()) {
// 1.創(chuàng)建全局隊(duì)列, 發(fā)送異步請(qǐng)求
DispatchQueue.global().async {
print("發(fā)送網(wǎng)絡(luò)請(qǐng)求:\(Thread.current)")
DispatchQueue.main.async {
print("回調(diào)主線程:\(Thread.current)")
finishedCallback("123", 30)
}
}
}
}
- 進(jìn)行網(wǎng)絡(luò)請(qǐng)求,請(qǐng)求到數(shù)據(jù)后利用閉包進(jìn)行回調(diào)
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
httpTools.requestData { (jsonData :String, age : Int) in
print("回到控制器,獲取到數(shù)據(jù)")
}
}
- 閉包寫(xiě)法總結(jié):
閉包的寫(xiě)法:
類型:(形參列表)->(返回值)
技巧:初學(xué)者定義閉包類型,直接寫(xiě)()->().再填充參數(shù)和返回值
值:
{
(形參) -> 返回值類型 in
// 執(zhí)行代碼
}
- 尾隨閉包寫(xiě)法:
- 如果閉包是函數(shù)的最后一個(gè)參數(shù),則可以將閉包寫(xiě)在()后面
- 如果函數(shù)只有一個(gè)參數(shù),并且這個(gè)參數(shù)是閉包,那么()可以不寫(xiě)
httpTool.loadRequest() {
print("回到主線程", NSThread.currentThread());
}
// 開(kāi)發(fā)中建議該寫(xiě)法
httpTool.loadRequest {
print("回到主線程", NSThread.currentThread());
}
閉包的循環(huán)引用
- 如果在HttpTool中有對(duì)閉包進(jìn)行強(qiáng)引用,則會(huì)形成循環(huán)引用
- 補(bǔ)充:在Swift中檢測(cè)一個(gè)對(duì)象是否銷毀,可以實(shí)現(xiàn)對(duì)象的
deinit
函數(shù)
// 析構(gòu)函數(shù)(相當(dāng)于OC中dealloc方法)
deinit {
print("ViewController----deinit")
}
- 循環(huán)引用的(實(shí)現(xiàn))
- 該實(shí)現(xiàn)是為了產(chǎn)生循環(huán)引用,而產(chǎn)生的循環(huán)引用
class HttpTools: NSObject {
var finishedCallback : ((_ jsonData : String, _ age : Int) -> ())?
func requestData(finishedCallback : @escaping (_ jsonData : String, _ age : Int) -> ()) {
self.finishedCallback = finishedCallback
// 1.創(chuàng)建全局隊(duì)列, 發(fā)送異步請(qǐng)求
DispatchQueue.global().async {
print("發(fā)送網(wǎng)絡(luò)請(qǐng)求:\(Thread.current)")
DispatchQueue.main.async {
print("回調(diào)主線程:\(Thread.current)")
finishedCallback("123", 30)
}
}
}
}
- swift中解決循環(huán)引用的方式
- 方案一:
- 使用weak,對(duì)當(dāng)前控制器使用弱引用
- 但是因?yàn)閟elf可能有值也可能沒(méi)有值,因此weakSelf是一個(gè)可選類型,在真正使用時(shí)可以對(duì)其強(qiáng)制解包(該處強(qiáng)制解包沒(méi)有問(wèn)題,因?yàn)榭刂破饕欢ù嬖?否則無(wú)法調(diào)用所在函數(shù))
// 解決方案一:
weak var weakSelf = self
httpTool.loadData {
print("加載數(shù)據(jù)完成,更新界面:", NSThread.currentThread())
weakSelf!.view.backgroundColor = UIColor.redColor()
}
- 方案二:
- 和方案一類型,只是書(shū)寫(xiě)方式更加簡(jiǎn)單
- 可以寫(xiě)在閉包中,并且在閉包中用到的self都是弱引用
httpTool.loadData {[weak self] () -> () in
print("加載數(shù)據(jù)完成,更新界面:", NSThread.currentThread())
self!.view.backgroundColor = UIColor.redColor()
}
- 方案三:(常用)
- 使用關(guān)鍵字
unowned
- 從行為上來(lái)說(shuō) unowned 更像OC中的 unsafe_unretained
- unowned 表示:即使它原來(lái)引用的對(duì)象被釋放了,仍然會(huì)保持對(duì)被已經(jīng)釋放了的對(duì)象的一個(gè) "無(wú)效的" 引用褂始,它不能是 Optional 值诸典,也不會(huì)被指向 nil
- 使用關(guān)鍵字
httpTool.loadData {[unowned self] () -> () in
print("加載數(shù)據(jù)完成,更新界面:", NSThread.currentThread())
self.view.backgroundColor = UIColor.redColor()
}
附上測(cè)試Demo,點(diǎn)我
懶加載
懶加載的介紹
- swift中也有懶加載的方式
- (蘋(píng)果的設(shè)計(jì)思想:希望所有的對(duì)象在使用時(shí)才真正加載到內(nèi)存中)
- 和OC不同的是swift有專門(mén)的關(guān)鍵字來(lái)實(shí)現(xiàn)懶加載
- lazy關(guān)鍵字可以用于定義某一個(gè)屬性懶加載
懶加載的使用
- 格式
lazy var 變量: 類型 = { 創(chuàng)建變量代碼 }()
- 懶加載的使用
// 懶加載的本質(zhì)是,在第一次使用的時(shí)候執(zhí)行閉包,將閉包的返回值賦值給屬性
// lazy的作用是只會(huì)賦值一次
lazy var array : [String] = {
() -> [String] in
return ["why", "lmj", "lnj"]
}()
訪問(wèn)權(quán)限
swift中的訪問(wèn)權(quán)限
- Swift 中的訪問(wèn)控制模型基于模塊和源文件這兩個(gè)概念
- internal : 在本模塊中都可以進(jìn)行訪問(wèn)
- fileprivate : 在當(dāng)前源文件中可以訪
- private : 在當(dāng)前class中可以訪問(wèn)(extension中也不可以訪問(wèn))
- open : 在其他模塊中可以訪問(wèn)
import UIKit
/*
1> interal: 內(nèi)部的
1.默認(rèn)情況下所有的類 屬性 方法的訪問(wèn)權(quán)限都是 interal
2. 在本模塊中(項(xiàng)目中)可以訪問(wèn)
2> private: 私有的
1. 只在本類中可以訪問(wèn)
3> open :公開(kāi)的
1.可以跨模塊(項(xiàng)目/包/target)都是可以訪問(wèn)
4> fileprivate: swift3.0
1. 只要是在當(dāng)前文件中都是可以進(jìn)行訪問(wèn)
*/
class ViewController: UIViewController {
var name : String = ""
private var age : Int = 0
fileprivate var height: Double = 0
override func viewDidLoad() {
super.viewDidLoad()
//訪問(wèn)name
name = "ahy"
print(name)
//訪問(wèn)age
age = 18
print(age)
//創(chuàng)建一個(gè)UIView 對(duì)象
let view = UIView()
view.alpha = 0.5
view.tag = 90
//訪問(wèn)height
height = 9.0
print(height)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}