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。
此文章为个人笔记,方便自己以及有需要的朋友查看,转载请注明出处!