10.Swift 中的闭包

本文深入探讨Swift闭包的使用,从排序、映射到自动闭包和尾随闭包,揭示闭包在Swift中的强大应用。包括闭包表达式语法、根据上下文推断类型、单表达式闭包隐式返回、参数名称缩写、运算符函数、尾随闭包、自动闭包与延迟操作等特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在Objective-C中, 我们有block, 在Swift中, 我们有闭包, 两者之间基本上一致, 没有多大的区别, 非要说起不同, 也就是声明的语法有些差异, 还有一些特性上的差异, 下面让我们来看看.


1.前言

在讲闭包之前, 我们来看看一个简单的例子:

let array = [1, 2, 3, 5, 3, 10, 20, 30]

func backwards(s1: Int, s2: Int) -> Bool {
    return s1 > s2
}

var reversed = array.sort(backwards)

print(reversed)

// 打印出来的结果:
// [30, 20, 10, 5, 3, 3, 2, 1]

这是一个排序的例子, 再想想, 貌似没有了更好的简洁方式了吧, 但这一切也只是在没有闭包之前, 下面让我们来看看闭包的强大之处.


2.闭包表达式语法

reversed = array.sort( { (s1: Int, s2: Int) -> Bool in return s1 > s2 } )

这个就是闭包表达式的语法, 完全不需要另外新建一个函数, 就可以完成排序的操作.


3.根据上下文推断类型

reversed = array.sort({s1, s2 in return s1 > s2})

这也是一种闭包的写法, Swift中有一个特性就是会根据上下文去推断类型, 而闭包也是可以如此的, 所以我们可以直接这么写.


4.单表达式闭包隐式返回

reversed = array.sort({ s1, s2 in s1 > s2})

在闭包里, 单行的闭包是可以不需要写return关键字的, 默认就会返回.


5.参数名称缩写

reversed = array.sort( { $0 > $1 } )

这种写法也是闭包的表达式, 不需要写参数名, 就可以直接排序.


6.运算符函数

reversed = array.sort(>)

这种写法也是闭包的表达式, 完全不需要任何参数, 直接写明一个运算符就可以完成排序, 但这种写法不太好, 只能完成一些比较简单的排序.


7.尾随闭包

所谓的尾随闭包, 就是自己声明一个闭包函数, 在别的地方去调用.

func someFunctionThatTakesAClosure(closure: () -> Void) {
    // 闭包函数体
}

// 写法一
someFunctionThatTakesAClosure({
    // 闭包函数体
})

// 写法二
someFunctionThatTakesAClosure() {
    // 闭包函数体
}

8.map函数

在Swfit原生当中, 有一个叫做map(_:)的函数, 它也是一个闭包类型, 下面让我们来看看.

let people = ["ZhangSan", "LiSi", "WangWu"]

let person = people.map { (var name) -> String in

    print(name)

    return name
}

map的用法和For-in有些类似, 它会映射数组的元素, 然后遍历, 直到遍历到最后一个元素为止.


9.自动闭包和闭包的延迟操作

var numberArray = [1, 2, 3, 4, 5, 6, 7, 8, 9]

print(numberArray.count)
// 输出的结果为: 9

let customerProvider = { numberArray.removeAtIndex(0) }

print(numberArray.count)
// 输出的结果为: 9

print("Now serving \(customerProvider())!")
// 输出的结果为: Now serving 1!

print(numberArray.count)
// 输出的结果为: 8

这里的customerProvider就相当于我们自定义的一个闭包函数, 虽然在闭包里, 已经移除了一个元素, 但该闭包并没有被调用, 所以元素不会被移除.


10.闭包的其他知识

这里还有一个叫做逃逸闭包, 和非逃逸闭包的概念:

所谓的逃逸闭包就是当一个闭包作为参数传到一个函数中,但是这个闭包在函数返回之后才被执行,我们称该闭包从函数中逃逸, 也就是说, 在函数外部可访问, 而非逃逸闭包就是只能在函数内部访问, 一旦函数运行结束, 闭包也就结束了.

这里有几个关键字: @noescape, @autoclosure, @autoclosure(escaping)

@noescape关键字来标注的闭包, 就会变成非逃逸闭包, 说明该闭包不能被函数外部所访问.

@autoclosure关键字来标注的参数, 则会自动把参数转变成自动闭包, 注意@autoclosure关键也是含有@noescape关键的特性, 所以用@autoclosure来标注的闭包参数是不可以逃逸的.

@autoclosure(escaping)关键字来标注的参数, 则会自动把参数转变成自动闭包, 并且可逃逸.

var numberArray = [1, 2, 3, 4, 5, 6, 7, 8, 9]

func someFunctionWithNoescapeClosure(@noescape closure: () -> Void) {
    closure()
}

func serveCunstomer(@autoclosure customerProvider: () -> Int) {
    print("Now serving \(customerProvider())!")
}

var customerProviders: [() -> Int] = []

func collectCustomerProviders(@autoclosure(escaping) customerProvider: () -> Int) {
    customerProviders.append(customerProvider)
}

这里有个例子, 有兴趣的朋友可以自己去研究看看, 如果想看更加详细的内容, 可以去参考官方文档.


这次就讲到这里, 下次继续

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值