-
1.闭包的介绍
- 闭包和OC中的block非常相似
- OC中的block是匿名的函数
- Swift中的闭包是一个特殊的函数
- block和闭包都经常用于回调
- 注意:闭包和block一样,第一次使用时可能不习惯它的语法,可以先按照使用简单的闭包,随着学习的深入,慢慢掌握其灵活的运用方法.
- 闭包和OC中的block非常相似
-
2.闭包的使用
-
1.先回顾一下block的使用
@property(nonatomic,strong) void(^myblock)(); // block 的格式: 返回值类型(^block名称) (参数列表) self.myblock = ^(){ NSLog(@"block的打印"); }; self.myblock();
-
2.闭包的基本介绍
/*
* 闭包和oc中的block非常相似
* oc中的block类似于匿名函数
* 闭包是用来定义函数
* 作用: block 是用于保存一段代码,在需要的时候执行
* 闭包也是用于保存一段代码,在需要的时候执行
* 做一个耗时的操作
*//* * 闭包的基本格式: in的含义是用来区分形参返回值和要执行的代码 * { (形参列表) -> (返回值) in 需要执行的代码 } * */ loadData { print("回调") } func loadData(request:()->()){ print("执行耗时操作") request() }
-
-
3.闭包的几种格式
-
1.将闭包通过实参传递给函数
loadData (request: { print("回调") }) func loadData(request:()->()){ print("执行耗时操作") request() }
-
-
2.如果闭包是函数的最后一个参数,那么闭包可以写在函数()的后面
loadData() {print("回调2") } func loadData(request:()->()){ print("执行耗时操作") request() }
-
3.如果函数只接受一个参数,并且这个参数是闭包,那么()可以省略
loadData {print("回调2") } func loadData(request:()->()){ print("执行耗时操作") request() }
4.闭包的返回值和参数
/*
* 两个闭包 创建一个 UIscrollview 上添加button
*
*
*/
let sc1 = createScrollview(buttonCount: { () -> Int in
return 15
}) { (index) -> UIView in
let width1 = 80
let button = UIButton()
button.backgroundColor = UIColor.red
button.frame = CGRect(x:index*width1,y:10,width:width1,height:80)
button.setTitle("标题\(index)", for: UIControlState(rawValue: 0))
return button
}
view.addSubview(sc1)
/*
* 要求定义一个方法来创建UIScrollView,
* 1.并且上面有多个按钮,必须通过闭包来告诉该方法
* 2.并且如何创建按钮也需要闭包来创建
*/
// 5.将scrollview添加到控制器的view上
// 特点: 没有写self
// swift推荐:能不写self就不写self
func createScrollview(buttonCount:()->Int,buttonIndex1: (_ num:Int)->UIView) -> UIScrollView {
// 数组的数量
let count = buttonCount()
// 1.创建scrollview
let sc = UIScrollView(frame: CGRect(x:0,y:64,width:414,height:100))
sc.backgroundColor = UIColor.blue
view.addSubview(sc)
// 2.在scrollview上放置button
for i in 0..<count {
/*
let button = UIButton()
button.backgroundColor = UIColor.red
button.frame = CGRect(x:i*width1,y:10,width:width1,height:80)
button.setTitle("标题\(i)", for: UIControlState(rawValue: 0))
sc.addSubview(button)
*/
let button = buttonIndex1(i)
sc.contentSize = CGSize(width:CGFloat(count) * button.bounds.width,height:100)
sc.addSubview(button)
}
return sc
}
-
5.循环引用
import UIKit class ViewController: UIViewController { /* * 在swift中,如果在某个类中定义一个属性,那么这个属性必须要初始化,否则就会报错 * 如果暂时不想初始化,那么可以在后面写上一个 ? 也就是可选类型 */ // 注意:这个是错误的写法,当前写法代表闭包的返回值可以是nil //var finsh: ()->()? // 下面是正确的写法 var finsh: (()->())? override func viewDidLoad() { super.viewDidLoad() weak var weakSelf = self loadata { print("回调") // 在swift开发中,能不写self就不写self,但是在闭包中必须写上self // 所以以后看到self基本上都是和闭包有关系 weakSelf!.view.backgroundColor = UIColor.brown } } func loadata(finsh:()->()) { print("执行耗时操作") finsh() } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } }
**循环引用解决:以上面的为例
方式一:
- 使用weak,对当前控制器使用弱引用
- 但是因为self可能有值也可能没有值,因此weakSelf是一个可选类型,在真正使用时可以对其强制解包(该处强制解包没有问题,因为控制器一定存在,否则无法调用所在函数)
weak var weakSelf = self
loadata {
print("回调")
// 在swift开发中,能不写self就不写self,但是在闭包中必须写上self
// 所以以后看到self基本上都是和闭包有关系
weakSelf!.view.backgroundColor = UIColor.brown
}
}
方式二:
- 和方案一类型,只是书写方式更加简单
- 可以写在闭包中,并且在闭包中用到的self都是弱引用
loadata { [weak self] () -> () in
print("回调")
// 在swift开发中,能不写self就不写self,但是在闭包中必须写上self
// 所以以后看到self基本上都是和闭包有关系
self!.view.backgroundColor = UIColor.brown
}
}
方式三:
- 使用关键字unowned
- 从行为上来说 unowned 更像OC中的 unsafe_unretained
- unowned 表示:即使它原来引用的对象被释放了,仍然会保持对被已经释放了的对象的一个 "无效的" 引用,它不能是 Optional 值,也不会被指向 nil
loadata { [unowned self] () -> () in
print("回调")
// 在swift开发中,能不写self就不写self,但是在闭包中必须写上self
// 所以以后看到self基本上都是和闭包有关系
self.view.backgroundColor = UIColor.brown
}
}