闭包的介绍
- 闭包和OC中的block非常相似
- OC中的block是匿名函数
- Swift中的闭包是一个特殊函数
- block和闭包都经常用于回调
闭包的使用
block的用法回顾
@interface HttpTool()
/**
* 回调block
*/
@property (nonatomic, copy) void(^callBack)();
@end
@implementation HttpTool
- (void)requestWithBlock:(void (^)())callBack
{
self.callBack = callBack;
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"正在进行网络请求: %@", [NSThread currentThread]);
dispatch_async(dispatch_get_main_queue(), ^{
callBack();
});
});
}
@end
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
NSLog(@"发出数据请求");
__weak typeof(self) weakSelf = self;
[self.httpTool requestWithBlock:^{
NSLog(@"获取到数据");
NSLog(@"更新界面: %@", [NSThread currentThread]);
weakSelf.view.backgroundColor = [UIColor redColor];
}];
}
block写法:
类型:
返回值(^block的名称)(block的参数)
值:
^(参数列表) {
// 需要执行的代码
}
使用闭包替代block
class HttpTool: NSObject {
// 闭包的类型:(参数列表)->(返回值)
// 建议:以后写闭包直接:()->()
func requestData(callBack:()->()) {
dispatch_async(dispatch_get_global_queue(0, 0)) {
() -> Void in
print("正在进行网络请求:\(NSThread.currentThread())")
dispatch_async(dispatch_get_main_queue(), {
() -> Void in
callBack()
})
}
}
}
httpTool.requestData({
() -> () in
print("已经请求到网络数据")
print("更新界面: \(NSThread.currentThread())")
})
闭包的写法:
类型:(形式参数)->(返回值)
技巧:初学者定义闭包类型,直接写()->().后再填充参数和返回值
值:
{
(形参) -> (返回值) in
// 需要执行代码
}
闭包的简写
- 如果闭包没有参数, 没有返回值, in和in之间的内容可以省略
httpTool.requestData({
print("已经请求到网络数据")
print("更新界面: \(NSThread.currentThread())")
})
- 如果闭包是函数的最后一个参数, 则可以将闭包写在()后面
- 如果函数只有一个参数, 并且这个参数是闭包, 那么()可以不写
httpTool.requestData(){
print("已经请求到网络数据")
print("更新界面: \(NSThread.currentThread())")
}
// 开发中建议的写法
httpTool.requestData{
print("已经请求到网络数据")
print("更新界面: \(NSThread.currentThread())")
}
闭包的循环引用
- 如果在HttpTool中有对闭包进行强引用, 则会形成循环引用
class HttpTool: NSObject {
var callBack: (()->())? // 定义属性,来强引用传入的闭包
func requestData(callBack:()->()) {
self.callBack = callBack;
dispatch_async(dispatch_get_global_queue(0, 0)) {
() -> Void in
print("正在进行网络请求:\(NSThread.currentThread())")
dispatch_async(dispatch_get_main_queue(), {
() -> Void in
callBack()
})
}
}
}
// 解决循环引用的方式一:
weak var weakSelf: ViewController? = self
httpTool.requestData {
print("已经请求到网络数据")
print("更新界面: \(NSThread.currentThread())")
weakSelf!.view.backgroundColor = UIColor.orangeColor()
}
// 解决循环引用的方式二:
// 该方式不能省略赋值时的:()->() in
httpTool.requestData {
[weak self]()->() in
print("已经请求到网络数据")
print("更新界面: \(NSThread.currentThread())")
self!.view.backgroundColor = UIColor.orangeColor()
}
// 解决循环引用的方法三:
// 该方式不能省略赋值时的:()->() in
// unowned
/*
__weak:当弱指针指向的对象销毁时,指针自动指向nil
__unsafe_unretained:当不安全指针指向的对象销毁时,指针依然指向之前的内存(可能会产生野指针)
*/
httpTool.requestData {
[unowned self] () -> () in
print("已经请求到网络数据")
print("更新界面: \(NSThread.currentThread())")
self.view.backgroundColor = UIColor.orangeColor()
}