swift block

Posted 博BOBO

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了swift block相关的知识,希望对你有一定的参考价值。

  • block闭包表达式

在 swift中可以用 func 定义一个函数,也可以用闭包表达式定义一个函数

func sum(v1:Int, v2:Int) -> Int  v1 + v2 
let sum2 =  (v1:Int, v2:Int) -> Int in
    return v1 + v2

sum(v1: 10, v2: 20)//func定义的函数
sum2(10, 20)//闭包表达式定义的函数
 func sun(param1:Int, param2:Int, test:( Int, Int) -> Int) 
    print(test(param1, param2))
 

 sun(param1:20 , param2:20, test:
    (v1:Int, v2:Int) -> Int in
    return v1 + v2
 )
//闭包表达式简写
 sun(param1:20 , param2:20, test:
    v1, v2 -> Int in
    return v1 + v2
 )
 sun(param1:20 , param2:20, test:
    v1, v2  in
    return v1 + v2
 )
//闭包表达式隐式返回
 sun(param1:20 , param2:20, test:
    v1, v2  in  v1 + v2
 )
//参数名称简写
sun(param1:20 , param2:20, test:
   $0 + $1
)
//函数式闭包
sun(param1: 2, param2: 3, test: +)

  • 尾随闭包

最后一个参数是闭包表达式的时候,可以独立于前面的参数,写在函数参数外面的闭包表达式,使结构看起来再加清晰整洁,属于结构优化,默认闭包表达式作为参数的时候采用尾随闭包的形式。

sun(param1: 12, param2: 13)  (v1:Int, v2:Int) -> Int in
    return v1 + v2
 
//尾随闭包表达式
sun(param1: 12, param2: 13)  v1, v2 in
     v1 + v2
 
//尾随闭包表达式简写
sun(param1: 20, param2: 12)  return $0 + $1 
//尾随闭包表达式简写
sun(param1: 10, param2: 12)  $0 + $1 
sun(param1: 10, param2: 12)  $0 + $1 

sun(param1: 2, param2: 3, test: +)

  • 自动闭包

顾名思义根据传入的参数,自动生成闭包;延迟执行,属于性能优化,除些之外也属于结构优化,调用者无需关心参数类型,用@autoclosure 修饰。

@autoclosure 只支持()->T 的格式参数,并且不仅仅只支持最后一个参数。

系统的合并运算符??属于自动闭包。

自动闭包允许你延迟处理,因此闭包内部的代码直到你调用它的时候才会运行。

//添加 @autoclosure 关键字, 当闭包被调用的时候,会返回被包装在其中的表达式的值
public func assert(_ condition: @autoclosure () -> Bool, _ message: @autoclosure () -> String = String(), file: StaticString = #file, line: UInt = #line) 
    if !condition() 
        print(message())
    

let number = 3
assert(number > 3, "number 不大于3")  //输出: number 不大于3
//自动闭包允许延迟处理
var person = ["zhangsan", "lisi", "wangwu", "zhailiu"]
print(person.count)    // 输出: 4
let deletePerson =  person.remove(at: 0) 
print(person.count)   //此时输出还是 4,因为没有调用闭包没有被调用,闭包里的代码没有被执行

//此时调用闭包
print(deletePerson())  //输出 "zhangsan"
print(person.count)    //输出: 3
//闭包作为实际参数传递给函数时,能获得同样的延时求值行为
//闭包作为实参, 可以显示的使用闭包
var person = ["zhangsan", "lisi", "wangwu", "zhailiu"]
func serve(customer customerProvider: () -> String) 
    print("Now serving \\(customerProvider())!")

//函数接受一个返回顾客名字的显式的闭包
serve(customer:  person.remove(at: 0) )  //打印: Now serving zhangsan!
//自动闭包作为实际参数
var person = ["zhangsan", "lisi", "wangwu", "zhailiu"]
//customerProvider 参数将自动转化为一个闭包,因为该参数被标记了 @autoclosure 特性
func serve(customer customerProvider: @autoclosure () -> String) 
    print("Now serving \\(customerProvider())!")

serve(customer: person.remove(at: 0))  //打印: Now serving zhangsan!

  • 自动+逃逸

//自动闭包允许逃逸,同时使用 @autoclosure 和 @escaping 标志
var customerInLine = ["zhangsan", "lisi", "wangwu", "zhaoliu"]
var customerProviders: [() -> String] = []
func collectionCustomerProviders(_ customerProvider: @autoclosure @escaping () -> String) 
    customerProviders.append(customerProvider)

print(customerProviders.count)   //打印: 0
collectionCustomerProviders(customerInLine.remove(at: 0))
collectionCustomerProviders(customerInLine.remove(at: 0))
print(customerInLine.count)   //打印: 4
print(customerProviders.count)  //打印: 2

for c in customerProviders 
    print("Now serving \\(c())")

/*
 Now serving zhangsan
 Now serving lisi
 */

collectCustomerProviders(_ : ) 函数并没有调用传入的 customerProvider 闭包,而是将闭包追加到了 customerProviders 数组中。
这个数组定义在函数作用域范围外,这意味着数组内的闭包能够在函数返回之后被调用。
因此,customerProvider 参数必须允许“逃逸”出函数作用域。

  • swift 闭包值捕获

  • 闭包可以对外部函数的变量、常量进行捕获;
  • 闭包捕获时机是在函数执行完,return 时再去捕获
  • 当函数里有多个闭包时,只会对变量、常量捕获一次,多个闭包对捕获的变量、常量共享
  • 闭包不会对全局变量进行捕获

闭包可以在其被定义的上下文中捕获常量或者变量。即是定义这些常量和变量的原作用域已经不存在了,闭包仍然可以在闭包函数体内引用和修改这些值。

  • 闭包类型

和类一样,闭包也是引用类型

  • 闭包

闭包和闭包表达式并不一是一个东西,半包表达式是函数的另外一种定义,而闭包是一个函数和它所捕获变量/常量环境的组合;

一般指定义在函数内部的函数;一般它捕获的是外层函数的局部变量/常量;

闭包和和闭包表达式的区别?

闭包表达式是:函数的另外一种表现形式,为了实现简介和高效,有不同的表现形式,例如自动闭包,尾随闭包;
闭包是:封装在函数中的函数或者闭包表达式,且捕获了局部变量的运行环境。它运用了闭包表达式,但闭包表达式不是闭包。

  •  循环引用的问题

    objective-c解决闭包的循环引用问题一般是先声明__weak typedef(weakSelf) = self;然后使用weakSelf对本类的属性调用。
    swift中也有类似于objective-c中的方法:首先是声明:weak var weakSelf = self;然后使用weakSelf对本类的属性调用。self可能会为nil,所以需要用var。

  • 闭包内修改外部变量

在objective-c中,我们通常使用__block来声明一个变量,这样就可以在闭包内对这个变量进行修改。
在swift中没有__block这种关键字,但是swift中的闭包是做了优化处理,是可以直接捕获上下文中的变量。所以可以直接在闭包中对变量进行修改。

以上是关于swift block的主要内容,如果未能解决你的问题,请参考以下文章

为啥在 Swift 的单数返回表达式中使用闭包简写变量必须详尽无遗?

swift中的block

Swift入坑--block的定义

简写的闭包数组:Xcode Swift:表达式太复杂,无法在合理的时间内解决

Swift 闭包 与 OC block区别

oc中block用swift怎么写了