Swift 闭包

  • 创建基础闭包
let driving = {
    print("创建基础闭包")
}
driving()
  • 在闭包中接受参数
let driving2 = {(place: String) in
    print("I'm going to \(place) in my car.")
}
  • 闭包和函数的一个区别:调用闭包时不使用参数标签
driving2("London")
  • 从闭包中返回值
let driving3 = {(place: String) in
    return "I'm going to \(place) in my car."
}
print("Yesterday, " + driving3("New York"))
  • 将闭包作为参数
func travel(action:() -> Void) {
    print("I'm getting ready to go.")
    action()
    print("I arrived!")
}
travel(action: driving)
  • 尾随闭包语法
travel {
    print("I'm drving in car.")
}

  • 当闭包接受参数时,将其用作参数
func travel2(action: (String) -> Void) {
    print("I'm getting ready to go.")
    action("ShangHai")
    print("I arrived!")
}

  • 使用结尾封闭语法调用函数travel2,闭包代码需要接收字符串
travel2{(place: String) in
    print("I'm going to \(place) in my car.")
}
  • 闭包返回值时,将其用作参数
func travel3(action: (String) -> String){
    print("I'm getting ready to go.")
    let description = action("ShangHai")
    print(description)
    print("I arrived!")
}
travel3{(place:String) -> String in
    return "I'm going to \(place) in my car."
}
  • 参数名称缩写

Swift可以为闭包的参数提供自动名称,这些名称以【$】命名,从0开始计数

travel3{
    //只有一行代码时可以省略【return】
    "I want to go to \($0)"
}

  • 具有多个参数的闭包
func myTravel(action: (String,Int) -> String){
    print("I'm getting ready to go.")
    let description = action("ShangHai",6)
    print(description)
    print("I arrived!")
}

myTravel{
    "I had go to \($0) \($1) times."
}
  • 从函数返回闭包

前一个【->】:指定函数的返回值(其实就是闭包)
后一个【->】:制定闭包的返回值

func xTravel() -> (String) -> Void {
    return {
        print("今天学习了\($0)")
    }
}
xTravel()("Swift")
  • 捕获值

若在闭包内部使用了函数中创建的值,则会发生闭包捕获

func xTravel2() -> (String) -> Void {
    var counter = 1
    return {
        print("今天学习了\($0) \(counter)小时")
        counter += 1
    }
}
let x2=xTravel2()
x2("SwiftUI")
x2("Swift")
x2("小黄书")

总结

  1. 闭包可以分配给变量,然后调用它们
  2. 闭包可以接受参数和返回值,例如常规函数
  3. 闭包可以作为参数传递给函数,并且这些闭包可以具有自己的参数和返回值
  4. 如果函数的最后一个参数是闭包,则可以使用尾随闭包语法
  5. Swift会自动提供诸如$0$1之类的参数缩写名称,但并非每个人都使用这个写法
  6. 如果在闭包内部使用外部值,则将捕获它们,以便闭包以后引用它们

本博文中的案例来自【100 Days of SwiftUI——闭包】

转载一个网友对闭包写法的总结
  • 什么是闭包

闭包:就是自包含的代码块,可以在代码中被传递和使用。
闭包,实际上就是OC里面的blocks,在其它语言里面就是匿名函数。

闭包在swift中有几种形式,我们的主题是闭包的简写,关于闭包更多的概念,就不详细讲解了。

  • 完整函数的写法
    我们用数组的sorted(by:)排序方法来举例。该方法会返回一个与原数组大小相同,内部元素不同的数组,对原数组,该方法不会修改。sorted(by:)方法接收一个函数参数,函数的类型为:(Int, Int) -> Bool。
let arr = [1,2,3,8,6,5,4]
//定义出排序函数
func sortedMethod(_ s1: Int, _ s2: Int) -> Bool {
    return s1 > s2
}
//排序
let new = arr.sorted(by: sortedMethod) //new的内容:8 6 5 4 3 2 1
  • 使用闭包的写法
sorted(by:)方法,可以接收一个闭包用来代替函数作为参数

//使用闭包。in关键字,表示闭包的参数和返回值类型定义已经完成,闭包函数体即将开始
let new1 = arr.sorted(by: { (s1: Int, s2: Int) -> Bool in
    return s1 > s2
}) //new的内容:8 6 5 4 3 2 1
  • 根据上下文推断类型
    因为闭包是作为sorted(by:)方法的参数传入的,所以闭包的参数和返回类型可以被推断出来。所以闭包的参数和返回值声明可以被省略。如下:
//省略参数和返回值声明
let new2 = arr.sorted(by: { s1, s2 in
    return s1 > s2
})

虽然说这样写很方便,但是会不利于阅读,完整的写完格式,能够提高代码的可读性。

  • 单表达式闭包隐式返回
    单行表达式的闭包可以省略return关键字。
    注意:必须是单行表达式的闭包才能省略return关键字
//单行表达式省略return关键字
let new3 = arr.sorted(by: { s1, s2 in
    s1 > s2
})
  • 参数名称缩写
    使用闭包来作为参数,swift提供了参数名称缩写功能。就是说,可以使用$0,$1,$2来依次使用参数,即使该参数没有被显式的定义。因此,可以省略掉in关键字和前方的参数。
//参数名称缩写,$0和$1分别代表s1和s2
let new4 = arr.sorted(by: { $0 > $1 })
  • 运算符方法
    实际上,由于 > 该符号实际上是一个函数,类型为(Int, Int) -> Bool,所以,可以更加简单的写。
//运算符方法
let new5 = arr.sorted(by: > )
  • 尾随闭包
    如果需要一个很长的闭包表达式作为最后一个参数传递给函数,可以使用尾随闭包来增强可读性。

注意点:
1.作为最后一个参数传递给函数。
2.使用尾随闭包可以不用写出其它参数标签

//尾随闭包
let new6 = arr.sorted() { $0 > $1 }

//如果闭包表达式是函数或者方法的唯一参数,可以省略()
let new7 = arr.sorted { $0 > $1 }
逃逸闭包(@escaping)

什么是逃逸闭包。
如果一个闭包被作为一个参数传递给一个函数,并且在函数return之后才被唤起执行,那么这个闭包是逃逸闭包。
并且这个闭包的参数是可以“逃出”这个函数体外的。

所有网络请求的函数,在完成调用请求后,直到响应返回,闭包才会被调用,所以这个类型的网络请求函数内等待响应的闭包就是逃逸闭包。这个类型的闭包,需要程序员手工加入一个@escaping标记才可以编译通过。

如下代码,展示了一个非逃逸闭包,和一个逃逸闭包。后者已经被标记了@escapings

class AppDelegate: UIResponder, UIApplicationDelegate {
    var window : UIWindow?
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        func syncRequest(callBack: ()->Void ) {
            callBack()
        }
        func asyncRequest( callBack: @escaping()->Void ) {
            DispatchQueue.main.asyncAfter(deadline: .now() + 1.0, execute: {
                callBack()
            })
        }
        syncRequest(){
            print("callback")
        }
        asyncRequest(){
            print("delay 1s callback")
        }
        window = UIWindow()
        window!.rootViewController = UIViewController()
        window!.rootViewController!.view.backgroundColor = .blue
        window!.makeKeyAndVisible()
        return true
    }
}

函数DispatchQueue.main.asyncAfter用来延时。此处延时1s再调用callback,演示了一个逃逸闭包的效果。

闭包可能需要引用当前上下文的变量,因此当调用者完成后,如果标记了逃逸闭包,那么当前调用的上下文依然会保持。如果在该标记的地方没有标记的话,会怎么样?不会在运行时报错,而是在编译期间就报错了。因为编译器知道你没有立即调用callback。好智能。

swift中闭包默认是不可逃逸的

关于创建默认不可逃逸闭包的好处: 最明显的好处就是编译器优化你的代码的性能和能力。如果编译器知道这个闭包是不可逃逸的,它可以关注内存管理的关键细节。

而且你可以在不可逃逸闭包里放心的使用self关键字,因为这个闭包总是在函数return之前执行,你不需要去使用一个弱引用去引用self.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值