Swift - 函数,闭包,解除闭包循环引用
摘要:闭包类似于 OC 的bock,但是比OC的block应用更广;在OC 中block是匿名的函数;在swift中 函数是特殊的闭包。
应用的场景:
1,异步执行完成回调
2,控制器间的回调
3,自定义视图回调
函数
- 函数的定义
函数 的定义 : 函数名(形参列表) -> 返回值
// 有参有返回值
func sum(x: Int,y: Int) -> Int {
return x + y
}
// 无参无返回值
func demo() {
print("安抚按时")
}
// 有参无返回值
func demo1(x: Int) -> () {
print("afdssd")
}
// 无参有返回值
func demo2() -> Int {
return ("afasf")
}
- 外部参数
外部参数 (就是咋形参前加一个名字,不会影响函数内部细节)
作用 : 让外部调用更加直观
func sum1(num1 x: Int, num2 y: Int) -> Int {
return x + y;
}
// 在swift 中 “—”可以忽略一切 不感兴趣的内容
func sum2(_ x: Int, _ y: Int) -> Int {
return x + y
}
- 函数默认值
通过给参数设置默认值,在调用的时候可以任意组合,如果不指定则使用默认值OC 中需要定义很多方法,以及方法实现,最终调用包含所有参数的那个函数swift中可以设置默认值,解决这种问题
func sum3(x: Int = 1, y: Int = 2) -> Int {
return x + y
}
闭包
- 闭包的定义
() -> () 没有参数没有返回值的 闭包
没有参数,没有返回值,可以省略 ,连 in 都神略了
let b1 = {
print("adfa")
}
闭包中参数返回值实现都是写在{}里面 {形参列表 -> 返回值 实现}
in 分割声明 与 实现
let b2 = {(x: Int) -> () in
print(x)
}
let b3 = {(x: Int) -> Int in
return x + 150
}
- 闭包的回调,尾随闭包
"尾随闭包" 如果函数最后一个参数是闭包,函数参数可以提前结束 最后一个参数直接用{}包装闭包的代码
func loadData(comlpant: @escaping (_ resoult: [String]) -> ()) -> () {
// 将任务添加到队列,指定执行人的函数(闭包) 以同步/异步 执行
DispatchQueue.global().async {
print("耗时操作\(Thread.current)")
// 消耗时间
Thread.sleep(forTimeInterval: 1)
let json = ["affas","afdasf","fd"]
// 主队列回调
DispatchQueue.main.async {
print("主线程更新UI\(Thread.current)")
// 闭包回调
comlpant(json)
}
}
}
// 调用
loadData { (resoult) in
print(resoult)
}
解除闭包循环引用
MRC: MRC 中没有weak,弱引用都是assign ,不会增加引用计数,但是指针指向对象释放,指针地址不会改变,会出现野指针异常
ARC : 在ARC中弱引用都用weak,不会增加引用计数,但是指针指向对象释放,指针地址会自动置为nil,更加安全__unsafe_unretained 与assign一样
实现循环引用
- 定义尾随闭包
// 第一步: 定义尾随闭包
func loadData (completion:@escaping ()->()) -> () {
// 第四步 self 持有闭包,造成互相持有,循环引用
complateCallBack = completion
// 异步执行
DispatchQueue.global().async {
print("这是耗时操作")
DispatchQueue.main.async {
// 回调闭包
completion()
}
}
}
- 闭包持有self. (注意:闭包中出现self 要特别小心,循环引用,循环引用的条件就是互相持有)
// 第二步: 闭包持有self,单方向的引用
loadData {
print(self.view);
}
- 定义闭包属性
//第三步 定义闭包属性
var complateCallBack:(()->())?
- 形成循环引用
// 类似OC dealloc
deinit {
print("类似dealloc")
}
解除循环引用
(1) 使用OC的方式 __Weak
注意: weak 可能被在运行时修改,指针指向的对象一旦被释放,指针会自动置为nil,指针地址改变了,所以 weak只能 用var来修饰
weak var WeakSelf = self
loadData {
print(WeakSelf?.view as Any)
}
(2) swift推荐方法
[weak self] 表示{}中所有的self都是弱引用,需要注意解包
loadData {[weak self] in
print(self?.view as Any)
}
(3)另一个方法,了解
[unowned self] 表示{}中所有self 都是assign,不会强引用,但是对象释放,指针地址不会变化,继续调用就会出现野指针问题
loadData {[unowned self] in
print(self.view)
}