Swift - 闭包

闭包表达式

{
    (参数列表) -> 返回值类型 in
    函数体代码...
}

var sum = {
    (v1: Int, v2: Int) -> Int in 
        return v1 + v2
}
sum(10, 20)

 闭包表达式简写

  • swift中形参和返回值类型都可以推断出来,所以可以省略类型声明;
  • 单行表达式可以省略return;
  • 参数可以用$0、$0代替;
var sum = {
    $0 + $0
}
sum(10, 20)

尾随闭包

函数的最后一个形参为闭包类型时,可以使用尾随闭包,即闭包可以写在小括号的外面

typealias sum = (Int, Int) -> Int

func calculateSum(v1: Int, v2: Int, v3: sum) -> Int { 
     return v3(v1, v2)
}
let num = calculateSum(v1: 10, v2: 20) { a, b in 
     a + b
}
print("num:", num)

逃逸闭包

逃逸闭包可以理解为,闭包形参没有在当前函数中直接调用,而是赋值于为变量,稍后调用,此时的形参闭包就是逃逸闭包,需用关键字@escaping;

var sumBlock: sum?
func calculateSum1(v1: Int, v2: Int, v3: @escaping sum) {
     self.sumBlock = v3
}
 calculateSum1(v1: 3, v2: 5) {
     $0 + $1
}
        
let num2 = self.sumBlock!(1, 1)
print("num2:", num2)

自动闭包

用一个单行表达式来表示闭包

 func testAutoclosure(v1: @autoclosure ()->String, v2: @autoclosure ()->()) {
      print("v1: ", v1())
      print("v2: ", v2())
}
 var str = "Hello"
print("0-----------str:", str)
testAutoclosure(v1: "iOS 你是最好的语言", v2: str.append(" Word"))
print("1-----------str:", str)

打印结果:
0-----------str: Hello
v1:  iOS 你是最好的语言
v2:  ()
1-----------str: Hello Word

循环引用
在swift中,修饰对象变量的关键字默认是strong;

常见循环引用的例子:

class ViewController: iCarBaseViewController {
    lazy var testBlock:(Bool)->Void = {
       return {
           (flag) in
           if flag {
               // self 引用了循环引用
               self.fun1(msg: "我是真的")
           }else {
               self.fun1(msg: "假的是他")
           }
       }
    }()

     override func viewDidLoad() {
        super.viewDidLoad()
        
        testBlock(false)
        testBlock(true)
     }
}

在上述代码中,iCarBaseViewController 的instance强引用了 testBlock 变量,而 testBlock 变量里面又强引用了 self(即iCarBaseViewController 的实例对象),所以会引起循环引用

解决方案:weak、unowned

// weak关键字
class ViewController: iCarBaseViewController {
    lazy var testBlock:(Bool)->Void = {
       return {
           [weak self](flag) in
           if flag {
               // self 引用了循环引用
               self?.fun1(msg: "我是真的")
           }else {
               self?.fun1(msg: "假的是他")
           }
       }
    }()

     override func viewDidLoad() {
        super.viewDidLoad()
        
        testBlock(false)
        testBlock(true)
     }
}

// unowned 关键字
class ViewController: iCarBaseViewController {
    lazy var testBlock:(Bool)->Void = {
       return {
           [unowned self](flag) in
           if flag {
               // self 引用了循环引用
               self.fun1(msg: "我是真的")
           }else {
               self.fun1(msg: "假的是他")
           }
       }
    }()

     override func viewDidLoad() {
        super.viewDidLoad()
        
        testBlock(false)
        testBlock(true)
     }
}

 如上所述,weak和unowned的关键字的区别在于,weak修饰的self,后续使用带有了?,即 weak修饰的对象,成了optional类型,在闭包中使用时,会进行是否是nil判断,减少了野指针crash的可能;而unowned修饰的对象,仅仅是弱引用,当修饰的对象销毁时,也不会将指向的对象地址置为nil,所以在使用防止存在野指针crash。

如上述例子,可以使用unowned修饰,因为iCarBaseViewController的对象销毁在testBlock的销毁之后,所以确保了不会存在野指针crash。

posted @ 2022-08-23 08:57  ~道一~  阅读(46)  评论(0编辑  收藏  举报