版权声明:本文为博主原创文章,未经博主同意不得转载。 https://blog.csdn.net/jiangqq781931404/article/details/32913421

文章转自:http://www.lookswift.com

闭包是个自包括的,能够在代码中传递的“块”。

。好吧,不纠结定义,继续。

swift的闭包,有点像C和Objective-C语言里的
代码块 {……} 
闭包能够捕捉而且保存在它所被定义的那个东西的上下文中定义的常量和变量。
事实上,在上一个笔记——函数,中的全局函数和嵌套函数,全都是闭包的特殊形式。
全局函数——是一个带有函数名的。并不捕捉不论什么值的函数。

嵌套函数——是一个带有函数名的而且从它被定义的外层函数中捕捉数值的函数。
闭包表达式——是一个不带函数名的。使用一种轻便的语法书写方式,而且能够从它被定义的外层函数中捕捉数值的函数。


从上面三个类型的函数的描写叙述,能够看出,事实上所谓的闭包(闭包表达式)。就是一个不带函数名的嵌套函数。仅仅只是,他的书写方式有点特别罢了。


swift
的闭包,鼓舞我们把他写得短小而且希望没有废话的方式。。。

我们都懂的,这种所谓的静止小巧短小尽量没有废话的方式。有时候会让人发狂,这正是闭包,这个玩意的难于理解之处吧!
只是。没关系,官方给的文档,足以让我们从一个让正人类能读懂的函数開始。慢慢变成一个非人正人类也可能会抓狂的函数的特殊形式——闭包。


刚才说到闭包推荐我们把函数尽量优化到所谓的短小和没有废话。那么先看一下。哪些部分会被“优化”掉:
1.
能够依据上下文推理出来的參数 以及 函数的返回值类型
2.
仅仅有一条语句构成的简单表达式的”return"keyword
3.
变量的名字
4.
Trailing closure syntax (后关闭的语法: 这个东西,我没有找到适合的解释。我自己的理解它相似于仅仅在函数的结尾才有返回的方式。也就是在不论什么一个函数体内,不论什么一个分支都不会打断函数的运行,一直到函数的最后一行的一个return或者无返回值之类的)
在swift的基本库中,有一个叫作sort的函数,它能够给Array中的元素排序,然后返回一个与传入的Array一样类型和元素个数的新的Array。
sort的原型:
sort(array:
T[], pred: (T, T) -> Bool)  //这是个泛型, pred是它内部用的。不用管,总之,參数2是个函数
假设參数2是个函数,这个不理解的话。还是先回头去把函数那部分复习一遍吧
这样可能不太easy读,那么我把它变形一下:
sort(myArray:
Int[],  (Int, Int) -> Bool)  //这是个Int型的处理方式
(感谢
swift技术交流第一平台(355277)的群友 packy(974871365) 指出之前写的时候,sort的右括号被我弄丢了,如今改好了 )
sort的第一个參数是个Int型数组,
第二个參数是个函数,这个函数有两个參数,返回值是Bool型
当然我们也能够把原型中的T换成其他的类型。比方:
sort(myArray:
String[],  (String, String) -> Bool)
sort(myArray:
Double[], (Double, Double) -> Bool)
以此类推,随便换成我们想要的形式
(泛型的意义如此)

let
names = [“Chris”, “Alex”, “Ewa”, “Barry”, “Daniella”]

func
myCompareFunc (s1: String, s2: String) -> Bool {   // 这个函数,跟sort的參数2 函数原型一样
 
   return s1 > s2
}
var
reversedNames = sort(names, myCompareFunc)  //得到了一个字母序倒序的数组
到这里。应该都非常easy理解了,sort的第一个參数。是个String数组,
第二个參数是个有两个參数而且返回Bool型的函数

sort会把names数组中的元素,按着它已经写好了的算法,取出某两个下标的值,然后传入到第二个參数定义的那个函数中,而第二个參数的函数是我们写的。假设參数1>
參数2,就返回true,这里是字符串,返回的字母表中字母的顺序,b排在a后面,所以b > a是true

前面说了,闭包有点像C语言和Objective-C里面的“代码块”,
所以。闭包的形式是这种:

                                                     //代码块開始
 
   (參数) -> 返回值类型 in              //注意这个语法: in 之后就是函数体了
 
        函数体

                                                     //代码块结束
更前面的时候。已经说了,闭包没有函数名。。。所以上面根本就没有函数名。但他仍然是个函数。


我们用闭包的形式。来改写上面写过的sort的调用。以及
myCompareFunc的定义:

reversedNames
= sort(names,  //參数2在以下

                                                     //代码块開始
 
   (s1: String, s2: String) -> Bool in     //注意这个语法: in 之后就是函数体了
 
        return s1 > s2                         

                                                     //代码块结束
) //
sort调用结束
这里sort的第二个參数,已经被我们替换成了上面提到的闭包的形式了
如今,我把一些换行符和一些空格以及凝视删掉,仅仅是删换行和空格和凝视哦:
reversedNames
= sort(names, {(s1:String, s2:String)->Bool in return s1 > s2} )  //对照一下,我没有多删东西吧
由于,这个闭包中的全部的參数类型(与sort的第一个參数的基本类型同样)
以及返回值类型(sort要求第二个函数的返回值类型为Bool)。全都是能够判断出来的,所以,类型能够省略,于是上面的这一条调用。就变成了:

reversedNames
= sort(names, {s1, s2 in return s1 > s2} )  //我仅仅删了參数类型和返回值类型
在上面的红字部分。提到。闭包中,能够省略的东西。2.仅仅有一条语句构成的简单表达式的”return”keyword,
所以,我们继续把return这个keyword也删掉, sort的调用就变成了:
reversedNames
= sort(names, {s1, s2 in s1 > s1})
到这里,是不是sort已经变得不太easy读了。

。。但还没完:
对于inline的闭包,
swift还提供了Shorthand Argument Names,作为參数的简写。以省去參数名,  $0代表第一个參数,$1代表第二个參数, $2……. 甚至连 in 都能够省了, 于是 sort调用的新版本号:
reversedNames
= sort(names, {$0 > $1})

操作符函数
上面的sort调用已经够短了。可是对于操作符
> 来说,它须要的是两个參数,而且返回值为Bool型,这正好符合了sort函数第2个參数所要求的函数形式,于是,我们能够把 > 当作函数,直接放在sort的第2个參数位置:

reversedNames
= sort(names, >)          //人类已经无法阻止闭包的简化了......
关于操作符作为函数,假设并不了解操作符重载的话,确实不好理解,那么请问度娘:“操作符重载”
是什么吧
Trailing
Closures
假设,闭包表达式作为函数的最后一个參数的时候。闭包表达式又非常长,不能像上面写成那么短的形式的话,那么,能够把闭包表达式,写在函数调用的外面。也就是()的后面,或者是以下:
func
myCallClosure(closure: () -> ()) {          //參数是个函数。名字叫closure而已。


 
   closure()              //用參数的名字closure, 调用传入的函数
}
myCallClosure({}) 
        //我仅仅是放了个空闭包{}在这里
假设{}中的内容非常长,我们能够把{}放在()外面:
myCallClosure()
{

}
这个看起来非常像函数的定义了,但他不是,由于函数名前面没有
funckeyword。

如今。我们回来看看sort,他的函数定义,也是最后一个參数要求传入函数,所以,我们能够把刚刚的sort,变成:
reversedNames
= sort(names) { $0 > $1 }    //我认为,连closure他爹都非常难一眼看出来了。

。。
我记得前几天,有群友,帖了这样一段代码,问:这是什么意思。今天,我才知道他一定是没有好好读手冊!。!!

。看下他帖的代码:

file:///Users/vincentpeng/Library/Containers/com.evernote.Evernote/Data/Library/Application%20Support/Evernote/accounts/Evernote-China/69033022/content/p181/292793c1dcf38eaa3818f2f39bf0116c.jpeg
通过上面闭包的学习,如今是不是非常easy看懂这个代码就是个闭包了?
仅仅只是map后面没有写()
至于这个numbers.map是怎么用的(numbers是个Array,map是Array的方法),这段代码的具体意思。手冊上都有非常详尽的解说,我就不列在这里。也不要再问这个问题了,不要搞得好像自己学习能力非常差一样。

。。
Capturing
Values
早些时候,提到了闭包能够捕捉并保存它的外层函数的常量和变量,接下来。我们来看看,有什么奇妙的事情,假设上面的闭包内容都理解了之后,这一段,事实上没啥好说的,直接上官方代码:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc3VwZXJnZXJt/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" border="0" alt="" style="border:0px;" />
file:///Users/vincentpeng/Library/Containers/com.evernote.Evernote/Data/Library/Application%20Support/Evernote/accounts/Evernote-China/69033022/content/p181/bf34207ce7cd71a0629611ae948abf11.jpeg
incrementor是个嵌套函数,
它返回了一个Int。 可是奇妙的是,他没有传入參数。而是使用了一个叫作runningTotal的外层函数makeIncrementor定义的一个局部变量。当makeIncrementor返回incrementor函数的时候,实际上是返回了incrementor函数的一个复制出来的实体函数(每次调用makeIncrementor的时候都会复制一个新的incrementor函数), 正由于闭包能够保存它外层函数定义的常量和变量,所以,当外层函数的作用域已经不存在的时候,它依旧能够使用那个常量或变量的值:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc3VwZXJnZXJt/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" border="0" alt="" style="border:0px;" />
file:///Users/vincentpeng/Library/Containers/com.evernote.Evernote/Data/Library/Application%20Support/Evernote/accounts/Evernote-China/69033022/content/p181/75dee77bae22d9b325161d13255d9238.jpeg
看到每次调用
incrementByTen(),得到的结果在递增了吧? 

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc3VwZXJnZXJt/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" border="0" alt="" style="border:0px;" />
file:///Users/vincentpeng/Library/Containers/com.evernote.Evernote/Data/Library/Application%20Support/Evernote/accounts/Evernote-China/69033022/content/p181/0e4357bf6cb1d726aae8e1c620687005.jpeg
这一段,也证明了我上面的猜:每次调用makeIncrementor的时候都会复制一个新的incrementor函数
闭包是引用类型

file:///Users/vincentpeng/Library/Containers/com.evernote.Evernote/Data/Library/Application%20Support/Evernote/accounts/Evernote-China/69033022/content/p181/54946750d12121807df6b88b210523bd.jpeg
这里并没有调用
makeIncrementor去复制一个新的函数,而仅仅是定义了一个变量 alsoIncrementByTen 被赋值成了 incrementByTen //这个函数在上面的时候,已经被调用了多次,正由于闭包是引用类型,这里的alsoIncrementByTen实际上仅仅是 incrementByTen 引用的那个之前复制出来的函数的新引用而已,于是。得到的结果是50.
本文章来自:雨燕开发人员:http://www.lookswift.com

swift开发学习笔记-闭包的更多相关文章

  1. 【前端】移动端Web开发学习笔记【2】 & flex布局

    上一篇:移动端Web开发学习笔记[1] meta标签 width设置的是layout viewport 的宽度 initial-scale=1.0 自带 width=device-width 最佳实践 ...

  2. 【前端】移动端Web开发学习笔记【1】

    下一篇:移动端Web开发学习笔记[2] Part 1: 两篇重要的博客 有两篇翻译过来的博客值得一看: 两个viewport的故事(第一部分) 两个viewport的故事(第二部分) 这两篇博客探讨了 ...

  3. 驱动开发学习笔记. 0.07 Uboot链接地址 加载地址 和 链接脚本地址

    驱动开发学习笔记. 0.07 Uboot链接地址 加载地址 和 链接脚本地址 最近重新看了乾龙_Heron的<ARM 上电启动及 Uboot 代码分析>(下简称<代码分析>) ...

  4. android开发学习笔记000

    使用书籍:<疯狂android讲义>——李刚著,2011年7月出版 虽然现在已2014,可我挑来跳去,还是以这本书开始我的android之旅吧. “疯狂源自梦想,技术成就辉煌.” 让我这个 ...

  5. 高性能Cordova App开发学习笔记

    高性能Cordova App开发学习笔记 文件结构 添加插件 构建准备 各个www的作用,prepare命令会将hello\www的内容会拷贝到platform下的wwww目录,知道该改哪里了吧?如果 ...

  6. Rest API 开发 学习笔记(转)

    Rest API 开发 学习笔记 概述 REST 从资源的角度来观察整个网络,分布在各处的资源由URI确定,而客户端的应用通过URI来获取资源的表示方式.获得这些表徵致使这些应用程序转变了其状态.随着 ...

  7. 步步为营 SharePoint 开发学习笔记系列总结

    转:http://www.cnblogs.com/springyangwc/archive/2011/08/03/2126763.html 概要 为时20多天的sharepoint开发学习笔记系列终于 ...

  8. Kinect开发学习笔记之(一)Kinect介绍和应用

    Kinect开发学习笔记之(一)Kinect介绍和应用 zouxy09@qq.com http://blog.csdn.net/zouxy09 一.Kinect简单介绍 Kinectfor Xbox ...

  9. ASP.NET Core Web开发学习笔记-1介绍篇

    ASP.NET Core Web开发学习笔记-1介绍篇 给大家说声报歉,从2012年个人情感破裂的那一天,本人的51CTO,CnBlogs,Csdn,QQ,Weboo就再也没有更新过.踏实的生活(曾辞 ...

随机推荐

  1. hdu1874最短路

    裸裸的最短路问题,将while(scanf("%d%d", &N, &M)!=EOF)粗心写为while(scanf("%d%d", & ...

  2. python GIL

    https://www.cnblogs.com/MnCu8261/p/6357633.html 全局解释器锁,同一时间只有一个线程获得GIL,

  3. Mac Pro 系统自带python路径

    /usr/local/Frameworks/Python.framework/Versions/2.7/bin

  4. Zookeeper协调分布式节点demo

    多台服务器和客户端通过第三方组件Zookeeper管理 public class DistributedServer { private static final String connectStri ...

  5. 2016.7.12 在navicat中用sql语句建表

    参考资料: http://jingyan.baidu.com/article/f0e83a25a8c4b022e5910116.html 即新建query,然后run. (1)点击要新建表的位置,选择 ...

  6. Flume 开发人员指南V1.5.2

    介绍 概述 Apache Flume是一个用来从非常多不同的源有效地收集.聚集和移动大量的日志数据到一个中心数据仓库的分布式的,可靠的和可用的系统. Apache Flume是Apache软件基金会的 ...

  7. 3、C++新的关键字

        C++ 添加了一些全新的关键字. 1.new     new 来进行动态内存的分配,而delect 则是进行内存的释放, 申请的方式: 变量申请: int *p = new int; // 申 ...

  8. 如何修改eclipse的默认字符集和修改中文乱码

    转载,以供以后学习.谢谢 有时候 java代码,导入eclipse中会出现 乱码的问题,通过修改字符集就可以解决. 看下面图片演示过程. 发表在 使用教程 | 标签为 eclipse, 乱码 | 留下 ...

  9. UITextField placeholder text color

    iOS6 and Later 改变UITextField 中占位符 提示文本的文字颜色 在新版本中(iOS6以后)iOS提供一种 Key = value 属性的方式,来改变UI的属性内容.以UITex ...

  10. BigDecimal的String类型

    java本身对浮点型的计算会丢失精度,这个一定要注意,必须要用BigDecimal的String类型才能解决精度的问题. BigDecimal一共有四个构造方法: 我们在计算商品价格的时候,一定要用B ...