前面写过一篇block的文章。swift看了看,闭包这块感觉block差不多。代码敲了敲,流程走一遍,有了一点理解。
1、闭包的简单使用
PS:还是习惯用block命名闭包
let addBlock:(Int, Int) -> (Int) = {
(a, b) -> Int in
return a+b;
}
let c:Int = addBlock(10, 15);
print(c);
如上,定义一个闭包,闭包名称是addBlock,闭包类型是:2个Int参数,返回值是Int。后面紧接着就实现了闭包。下面就是闭包的调用,用一个Int类型接收闭包的返回值。over。
这么定义闭包的格式看着眼熟不?
let data:String = "我是网络数据---哈哈"
没错,和定义一个普通的对象一样,let 名称:类型 = 结果,
闭包就是一个函数的类型。类型就是什么参数返回神结果
比如这个闭包类型就是2个Int参数返回一个Int结果。
这就是闭包的简单使用。至于其他的书写方式,在什么情况下,啥时候省略void,省略in,省略形参啥的,这里不做讨论。万变不离其宗,都是这个格式的变形而已。
再看一个swift函数的定义和使用
//函数的声明、实现
func stadFunc(pa:Int, pb:Int) -> Int{
return pa + pb;
}
//调用函数
let d = stadFunc(pa: 10, pb: 3);
print(d);
和闭包一样,同样的定义,参数、返回值、实现的大括号部分等等。
以前block的时候就说过block其实就是函数的变形,闭包同理。
如果闭包都这么简单的使用,和普通函数没啥区别,就体现不出它的价值了。
2、闭包的回调
以前block就说回调的功能,这个功能才是主要的用途,可以传递数据、发送个通知啥的。
上面说过,闭包可以看作函数,具有这个函数的类型。既然有了类型,就和普通数据一样,可以当做另外一个函数的参数。
func textAddBlock(block:(Int, Int) -> Void, failBlock:()->Void){
let resultA = 11;
let resultB = 12;
print("打印1")
block(resultA, resultB)
}
textAddBlock(block: { (pa:Int, pb:Int) in
let result = pa + pb;
print("block结果打印\(result)")
}) {
print("failBlock打印2222")
};
上面的代码,我定义了2个闭包,当做参数传递给另外一个函数了。
类似 func stadFunc(pa:Int, pb:Int) -> Int 函数中传了2个Int类型的参数。
既然强调了几遍闭包就是函数的概念。那么闭包使用起来和函数一样,实现和调用一个都不少。
回调的巧妙之处在于,一个函数是另一个函数的参数,闭包作为参数,就需要被另外一个函数使用,就像a:Int参数,在函数的使用部分用起来可以是return a;。闭包使用起来,就是调用它了。(参考上面代码)
实现的代码在另一个函数的调用部分,所以可以把这个函数实现部分的数据传递过来。就实现了回调。
所以回调的本质就是两个函数的声明实现代码和调用代码相互嵌套书写。
3、逃逸闭包
简单来说,就是一个闭包的调用的时候,它所在的函数实现部分已经结束了。常用于网络请求等多线程中。
比如,我写了个简单网络请求工具(什么都是假的)
import UIKit
class NetWokrTool: NSObject {
func requestResult(successBlock:@escaping (String, Bool)->Void, failBlokc:@escaping (Bool)->Void) -> Void {
DispatchQueue.global().async {
sleep(2);
let data = "我是网络数据---哈哈"
let result:Bool = true;
successBlock(data, result);
failBlokc(result);
};
}
}
定义实现了一个请求的方法,其中把2个闭包作为参数,一个成功,一个失败的闭包。模拟了子线程请求。
得到了网络数据和请求结果后,通过调用闭包,把数据传递出去。
由于需要在控制器中的主线程中调用这个工具类,正常走下去,走到这个方法里,发现有了子线程,主线程不管这个,继续走,直到这个函数走完,函数的生命周期就结束了。但是函数走完了,子线程还在工作,里面的代码还没结束,导致闭包的生命周期比这个函数还长,不会在相关函数结束后释放。所以需要逃出这个函数的掌控才能工作,用@escaping标记为逃逸闭包。其实是为了内存的释放。(感觉类似block的弱引用的作用差不多)
在控制器中调用这个工具类
let tool:NetWokrTool = NetWokrTool();
tool.requestResult(successBlock: { (data, result) in
print(data,result)
}) { (result) in
print(result);
};
结果:
回调结果.png
最终把请求得到的数据和结果回调到了控制器中。
网友评论