闭包的介绍
函数是闭包的一种
类似于OC语言的block
闭包表达式(匿名函数) -- 能够捕获上下文中的值
语法: in关键字的目的是便于区分返回值和执行语句
闭包表达式的类型和函数的类型一样, 是参数加上返回值, 也就是in之前的部分
{
(参数) -> 返回值类型 in
执行语句
}
闭包简写
- 1.如果没有参数, 没有返回值, in和in之前的东西可以省略
- 2.如果闭包是函数的最后一个参数, 可以写在()后面 -- 尾随闭包
- 3.如果只有一个闭包参数, 那么()也可以省略 -- 尾随闭包
闭包使用:使用闭包代替block
- 定义网络请求的类
class HttpRequestTool: NSObject {
var callBack:(()->())?
func loadData(callBack: () -> ()) {
self.callBack = callBack
DispatchQueue.global(attributes: DispatchQueue.GlobalAttributes(rawValue: UInt64(0))).async {
print("网络请求数据:", Thread.current())
DispatchQueue.main.async(execute: {
callBack()
})
}
}
}
- 进行网络请求,请求到数据后利用闭包进行回调
class ViewController: UIViewController {
var httpTools : HttpRequestTool = HttpRequestTool()
override func viewDidLoad() {
super.viewDidLoad()
httpTools.loadData {
print("加载数据完成,更新界面:", Thread.current())
}
}
}
闭包的循环引用
- 如果在HttpTool中有对闭包进行强引用,则会形成循环引用
- 在Swift中检测一个对象是否销毁,可以实现对象的deinit函数
在xcode8可以利用内存图分析循环引用:
例如:这样写会造成循环引用
httpTools.loadData {
print("load data finish")
self.view.backgroundColor = UIColor.red()
}
deinit {
print("控制器销毁了")
}
通过内存分析图查看表现为:
绿色的为出现循环引用.并且没用打印控制器销毁.改为如下代码:
weak var weakSelf = self
httpTools.loadData {
print("load data finish")
weakSelf?.view.backgroundColor = UIColor.red()
}
deinit {
print("控制器销毁了")
}
通过内存分析图查看表现为:
绿色消除,打印控制器销毁
// 析构函数(相当于OC中dealloc方法)
deinit {
print("ViewController----deinit")
}
swift中解决循环引用的方式
- 方案一:使用weak,对当前控制器使用弱引用,但是因为self可能有值也可能没有值,因此weakSelf是一个可选类型,在真正使用时可以对其强制解包(该处强制解包没有问题,因为控制器一定存在,否则无法调用所在函数)
weak var weakSelf = self
httpTools.loadData {
print("load data finish")
weakSelf?.view.backgroundColor = UIColor.red()
}
- 方案二:和方案一类型,只是书写方式更加简单,可以写在闭包中,并且在闭包中用到的self都是弱引用
httpTools.loadData {[weak self] () -> () in
print("load data finish")
self?.view.backgroundColor = UIColor.red()
}
- 方案三:使用关键字unowned,从行为上来说 unowned 更像OC中的 unsafe_unretained,unowned 表示:即使它原来引用的对象被释放了,仍然会保持对被已经释放了的对象的一个 "无效的" 引用,它不能是 Optional 值,也不会被指向 nil
httpTools.loadData {[unowned self] () -> () in
print("load data finish")
self.view.backgroundColor = UIColor.red()
}
网友评论