Swift 5从零到精通iOS开发训练营
上QQ阅读APP看书,第一时间看更新

5.3 理解闭包结构

闭包结构对于编程初学者来说可能会难以理解,在学习闭包的过程中,读者首先应该理解闭包的结构与实质。

5.3.1 闭包的语法结构

使用Xcode开发工具创建一个名为Closures的Playground文件,接下来将在其中进行代码的演练。5.2节向读者介绍了有关函数的内容,函数的设计思路是将有一定功能的代码块包装在一起,通过函数名实现复用。闭包和函数有着类似的作用,然而闭包的设计大多数情况下并不是为了代码的复用,而是传递功能代码块和处理回调结构。首先,一个完整的函数包含函数名、参数列表、返回值和函数体,示例如下:

     //标准函数,这个函数的功能是计算某个整数的平方
     func myFunc(param:Int)->Int{
        return param*param
     }

将上面函数的功能使用闭包来实现,代码如下:

     //闭包的实现方式
     let myClosures = {(param:Int)->Int in
        return param*param
     }

上面的代码创建了一个名为myClosures的闭包常量,闭包在语法上有这样的标准结构:{(参数列表)->返回值in闭包体}。首先闭包的最外层由大括号包围,内部由闭包关键字in来进行分割,关键字in前面为闭包结构的参数列表和返回值,其书写规则与函数一致,关键字in后面为闭包体,用于实现具体功能。上面示例的闭包和函数原理上完全相同,并且闭包也可以像函数一样被调用,示例代码如下:

     //对函数进行调用,将返回9
     myFunc(param: 3)
     //对闭包进行调用,将返回9
     myClosures(3)

与函数不同的是,闭包的返回值是可以省略的,在闭包体中,如果有return返回,则闭包会自动将return的数据类型作为返回值类型,上面的闭包代码也可以简写为如下样式:

     //闭包的实现方式
     let myClosures = {(param:Int) in
        return param*param
     }

5.3.2 通过实现一个排序函数来深入理解闭包

在实践中分析与解决问题是学习编程的一条捷径。本小节将带领读者通过分析问题、探讨解决方案、进行初步实现、优化实现方式等一步一步深入了解闭包的用法。学习这种分析解决问题的方式在编程中十分有益,其思路如图5-1所示。

图5-1 分析与解决问题的思路

在实际开发中,开发者经常会遇到不同的排序需求,例如按商品价格排序、按文章热度排序、按消息时间先后排序、按学生成绩排序等。很多情况下,开发者要排序的对象并不是简单的数字类型值或者字符串类型值,而是自定义的复杂对象,也就是开发者常用的类。对于这种类型的排序需求,应该如何实现呢?首先应该明确需求问题,如下:

(1)应该实现一个函数来对数组类型排序。

(2)数组中的元素可以是任意的复杂类型。

实现根据复杂类型数据中的某一个属性进行排序,例如学生的成绩。

(1)针对上面提出的需求问题,设计初步的实现思路。

(2)以通用的数组类型作为函数的参数。

若要实现对自定义复杂类型的排序操作,则需要将排序算法作为参数传入函数。

编写函数的结构示例如下:

提示

Any在Swift语言中代表任意类型。

mySort()函数中需要传入两个参数,一个是要进行排序的数组数据,另一个是一个闭包排序方法,这个闭包有两个Any类型的参数,表示数组中两个相邻的元素。第1个参数表示前一个元素,第2个参数表示后一个元素,这个闭包有一个Bool类型的返回值,返回true则表示正向排序,即参数中的第1个元素和第2个元素不交换位置,返回false表示逆向排序,即参数中的第1个元素和第2个元素交换位置。之后,根据上面的分析来对mySort函数进行实现,代码如下:

如以上代码所示,使用了冒泡排序算法来进行排序操作,而具体两个元素的排序规则是由闭包sortClosure来实现的。swapAt()函数是Swift语言中的一个交换函数,用来实现数组元素的交换,由于需要对原数组数据进行操作,因此需要使用inout类型的数组参数。

先使用整型数组来对编写的排序函数进行测试,代码如下:

提示

as!的作用是类型转换。

编写一个自定义的类来进行排序测试,示例如下:

以上代码模拟了一个学生类,每一个学生对象由名字和分数组成,闭包实现了对学生分数的排序规则。

提示

上面的代码在定义学生类的时候遵守了CustomStringConvertible协议,实现这个协议的description方法可以自定义类对象的打印信息,在代码调试时非常好用。