Swift学习笔记之闭包

简介 (真的很简)

闭包的完整形态是这个样子的:

    { (parameters) -> returnType in
        statements
    }

写在一行里就是这样:

    {(parameters) -> (returnType) in statements}

形式

闭包以三种形式存在:

1.全局的函数都是闭包,它们有自己的名字,但是没有捕获任何值。
2.内嵌的函数都是闭包,它们有自己的名字,而且从包含他们的函数里捕获值。
3.闭包表达式都是闭包,它们没有自己的名字,通过轻量级的语法定义并且可以从上下文中捕获值。

捕获值

闭包可以捕获上下文的值,然后把它存储下来。至于存储的是引用还是拷贝,Swift 会决定捕获引用还是拷贝值,也会处理变量的内存管理操作。

下面这个例子可以说明很多问题:

    func makeIncrementor(forIncrement amount: Int) -> () -> Int {
        var runningTotal = 0
        func incrementor() -> Int {
            runningTotal += amount
            return runningTotal
        }
        return incrementor
    }

    let incrementByTen = makeIncrementor(forIncrement: 10)
    incrementByTen()    // runningTotal = 10
    incrementByTen()    // runningTotal = 20
    incrementByTen()    // runningTotal = 30

    let incrementByTen2 = makeIncrementor(forIncrement: 10)
    incrementByTen2()    // runningTotal = 10

    let incrementByTen3 = incrementByTen
    incrementByTen()    // runningTotal = 40

因为 incrementByTen2 声明了一个全新的闭包,所以 runningTotal 并没有继续接着上面的计数。而 incrementByTen3 和 incrementByTen 指向的是同一个闭包,所以 runningTotal 的值是累加的。

参数缩写

我们可以直接用 $0 $1 $2 这种来依次定义闭包的参数。比如 sorted 函数:

    var reversed = sorted(["c","a","d","b"], { $0 > $1 })   // d c b a

尾随闭包

我一直觉得闭包最后这个 }) 很难看,在 JS 中随处可见这种情况。如果闭包是函数的最后一个参数,Swift 提供了尾随闭包 (Trailing Closures) 解决这个审美问题:

    // 以下是不使用尾随闭包进行函数调用
    someFunc({
        // 闭包主体部分
    })

    // 以下是使用尾随闭包进行函数调用
    someFunc() {
      // 闭包主体部分
    }

OK那么前面那个排序的可以用尾随闭包这么改写:

    var reversed = sorted(["c","a","d","b"]) { $0 > $1 } // d c b a

如果除了闭包没有其他参数了,甚至可以把小括号也去掉。

还记得我们前面写的 map 、 reduce 、 filter 三元大将吗?用尾随闭包可以让它们变得更好看。比如前面那个选出大于30的数字的 filter 就可以这样写:

    var oldArray = [10,20,45,32]
    var filteredArray  = oldArray.filter{
        return $0 > 30
    }

    println(filteredArray) // [45, 32]

变形

变形金刚神马的最有爱了。总结一下 closure 的变形大致有以下几种形态:

    [1, 2, 3].map( { (i: Int) ->Int in return i * 2 } )
    [1, 2, 3].map( { i in return i * 2 } )
    [1, 2, 3].map( { i in i * 2 } )
    [1, 2, 3].map( { $0 * 2 } )
    [1, 2, 3].map() { $0 * 2 }
    [1, 2, 3].map { $0 * 2 }

对比

通过 UIView 的 animateWithDuration 方法对 block 和 closure 进行简单的对比。

block 版本:

    [UIView animateWithDuration:1 animations:^{
        // DO SOMETHING
    } completion:^(BOOL finished) {
        NSLog(@"OVER");
    }];

closure 版本:

    UIView.animateWithDuration(1, animations: { () in
        // DO SOMETHING
        }, completion:{(Bool)  in
            println("OVER")
        })

可以看到原来的 ^ 符号已经不复存在,取而代之的是加在参数和返回值后面的 in 。注意,如果有 in 的话,就算没有参数没有返回值也一定需要 () ,否则会报错。

总结

和 Objective-C 的 FuckingBlock 一样,Swift 出来之后 FuckingClosure 也就应运而生。总结了 Closure 的常用语法和格式:

    // 作为变量
    var closureName: (parameterTypes) -> (returnType)

    // 作为可选类型的变量
    var closureName: ((parameterTypes) -> (returnType))?

    // 做为一个别名
    typealias closureType = (parameterTypes) -> (returnType)

    // 作为函数的参数
    func({(parameterTypes) -> (returnType) in statements})

    // 作为函数的参数
    array.sort({ (item1: Int, item2: Int) -> Bool in return item1 < item2 })

    // 作为函数的参数 - 隐含参数类型
    array.sort({ (item1, item2) -> Bool in return item1 < item2 })

    // 作为函数的参数 - 隐含返回类型
    array.sort({ (item1, item2) in return item1 < item2 })

    // 作为函数的参数 - 尾随闭包
    array.sort { (item1, item2) in return item1 < item2 }

    // 作为函数的参数 - 通过数字表示参数
    array.sort { return $0 < $1 }

    // 作为函数的参数 - 尾随闭包且隐含返回类型
    array.sort { $0 < $1 }

    // 作为函数的参数 - 引用已存在的函数
    array.sort(<)

References

  知识来源:http://lib.csdn.net/article/swift/474

时间: 2024-10-08 04:51:06

Swift学习笔记之闭包的相关文章

swift学习笔记(六)析构过程和使用闭包对属性进行默认值赋值

一.通过闭包和函数实现属性的默认值 当某个存储属性的默认值需要定制时,可以通过闭包或全局函数来为其提供定制的默认值. 注:全局函数结构体和枚举使用关键字static标注    函数则使用class关键字标注 当对一个属性使用闭包函数进行赋值时,每当此属性所述的类型被创建实例时,对应的闭包或函数会被调用,而他们的返回值会被作为属性的默认值. ESC: Class SomeCLass{ let someProperty:SomeType={ //给someProperty赋一个默认值 //返回一个与

Swift学习笔记七:闭包

闭包可以 捕获 和存储其所在上下文中任意常量和变量的引用. Swift 会为您管理在 捕获 过程中涉及到的内存操作. 在 函数 章节中介绍的全局和嵌套函数实际上也是特殊的闭包,闭包采取如下三种形式之一: 1. 全局函数是一个有名字但不会捕获任何值的闭包 2. 嵌套函数是一个有名字并可以捕获其封闭函数域内值的闭包 3. 闭包表达式是一个可以捕获其上下文中变量或常量值的没有名字的闭包 一.闭包表达式 闭包函数类似于Objective-C中的block.下面我们用事实说话: let counts =

swift学习笔记(三)关于拷贝和引用

在swift提供的基本数据类型中,包括Int ,Float,Double,String,Enumeration,Structure,Dictionary都属于值拷贝类型. 闭包和函数同属引用类型 捕获则为拷贝.捕获即定义这些常量和变量的原作用域已不存在,闭包仍然可以在闭包函数体内引用和修改这些值 class属于引用类型. Array的情况稍微复杂一些,下面主要对集合类型进行分析: 一.关于Dictionary:无论何时将一个字典实例赋给一个常量,或者传递给一个函数方法时,在赋值或调用发生时,都会

Swift学习笔记十:属性

1.存储属性       1. 作为特定类或结构实例的一部分,存储属性存储着常量或者变量的值.存储属性可分为变量存储属性(关键字var描述)和常量存储属性(关键字let描述). struct student{ let name = "" var score = 0 } let a = student(name:"小笨狼",score:96)           注意:                ① 定义储存属性时,需要为每一个属性定义一个默认值.在初始化的时候,

Swift学习笔记十四:构造(Initialization)

类和结构体在实例创建时,必须为所有存储型属性设置合适的初始值.存储型属性的值不能处于一个未知的状态. 你可以在构造器中为存储型属性赋初值,也可以在定义属性时为其设置默认值.以下章节将详细介绍这两种方法. 注意: 当你为存储型属性设置默认值或者在构造器中为其赋值时,它们的值是被直接设置的,不会触发任何属性观测器(property observers). 一.基本语法 class Human{ var name :String init(){ name = "human" } init(n

SWIFT学习笔记05

1.Swift 无需写break,所以不会发生这种贯穿(fallthrough)的情况.2.//用不到变量名,可用"_"替换 for _ in 1...power { answer *= base } 3.case 可以匹配更多的类型模式,包括区间匹配(range matching),元组(tuple)和特定类型的描述. 可以这样用case case 1...3: naturalCount = "a few" 4.如果存在多个匹配,那么只会执行第一个被匹配到的 ca

SWIFT学习笔记02

1.//下面的这些浮点字面量都等于十进制的12.1875: let decimalDouble = 12.1875 let exponentDouble = 1.21875e1 let hexadecimalDouble = 0xC.3p0//==12+3*(1/16) 2.//类型别名,用typealias关键字来定义类型别名 typealias AudioSample = UInt16 var maxAmplitudeFound = AudioSample.min 3.//元组 let ht

Swift学习笔记十二:下标脚本(subscript)

下标脚本就是对一个东西通过索引,快速取值的一种语法,例如数组的a[0].这就是一个下标脚本.通过索引0来快速取值.在Swift中,我们可以对类(Class).结构体(structure)和枚举(enumeration)中自己定义下标脚本的语法 一.常规定义 class Student{ var scores:Int[] = Array(count:5,repeatedValue:0) subscript(index:Int) -> Int{ get{ return scores[index];

Swift学习笔记四:数组和字典

最近一个月都在专心做unity3d的斗地主游戏,从早到晚,最后总算是搞出来了,其中的心酸只有自己知道.最近才有功夫闲下来,还是学习学习之前的老本行--asp.net,现在用.net做项目流行MVC,而不是之前的三层,既然技术在更新,只能不断学习,以适应新的技术潮流! 创建MVC工程 1.打开Visual studio2012,新建MVC4工程 2.选择工程属性,创建MVC工程 3.生成工程的目录 App_Start:启动文件的配置信息,包括很重要的RouteConfig路由注册信息 Conten