- 1.闭包的介绍
- 闭包和OC中的block非常相似
- OC中的block是匿名的函数
- Swift中的闭包是一个特殊的函数
- block和闭包都经常用于回调
- 注意:闭包和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 } }