Swift入门教程系列6-闭包

来源:互联网 发布:安卓博德之门2修改数据 编辑:程序博客网 时间:2024/05/01 19:17
闭包
闭包是什么,如果你接触过Objective C,那么闭包类似于其中的block
闭包是一种自包含的函数代码块,可以被传递和使用(简单理解就是一种简化了的函数类型)
闭包可以捕获和存储上下文的任意常量和变量的引用,注意是引用
swfit鼓励使用闭包,因为其小巧,简洁。
闭包表达式
{
   (参数1,参数2,...)->返回值类型 in
    执行语句
}

闭包表达式以其小巧的特点,经常用作函数的参数:当一个函数需要另一个函数作为参数的时候,闭包能够很好地简化代码量,增加代码的灵活性。
通过闭包的定义可以看出,全局函数和嵌套函数是特殊的闭包
  1. 全局函数是一个不会捕获任何值的闭包
  2. 嵌套函数是一个有名字并且可以捕获其封闭函数域内值得闭包
  3. 闭包表达式是一个可以捕获上下文中常量或者变量值得闭包
首先介绍两个函数
sort 和sorted
sort(&array[T],isOrderdBefore:(T,T)->Bool)[C.Generator.Element] sorted(source C,isOrderdBefore(C.Generator.Element,C.Generator.Element)->Bool)

两个函数都可以对数组排序
差别是,sort函数传入引用,直接对传入的数据进行操作。sorted函数传入值,返回排序好的数组

官方文档里采用sorted函数的讲解非常直白透彻,本文采用相似代码来讲解,最后通过GCD,和UIView.animateWithDuration两个使用情景来讲解闭包的使用
通过上述sort的说明可以看出,sort函数需要一个(T,T)->Bool类型的闭包函数
这里T类似于C++的模板,表示类型
如果我们定义一个
var array = [1,3,4,2],如果我们想要对其使用sort
则需要的闭包函数类型为(Int,Int)->Bool
一 从一个例子理解闭包
1、使用函数类型
定义一个函数
func status(lhs:Int,rhs:Int)->Bool{    return lhs < rhs   }sort(&array,status)array.description
这里,我们传入一个函数类型
初始的方法代码量很大,很复杂,所以,接下来一步步简化


2、使用闭包表达式
sort(&array,{(lhs:Int,rhs:Int)->Bool in return lhs < rhs})array.description
这里我们使用到了闭包
{(rhs:Int,rhs:Int)->Bool in return lhs < rhs}

3、闭包表达式类型推断
因为sort函数这样定义
sort(&array[T],isOrderdBefore:(T,T)->Bool)
所以,编译器可以猜出闭包表达式中的类型是和数组的类型一致的,也就是说,在本文的例子中
闭包表达式的两个参数类型都是Int,至于返回值一定是Bool,因为编译器有如此猜测,我们可以这么写
sort(&array,{lhs,rhs in return lhs < rhs})

4、单表达式隐式返回
由于上述闭包的表达式只有return lhs < rhs
所以,及时省略return也不会产生歧义,编译器会推断这一行的执行结果作为返回值
sort(&array,{lhs,rhs in lhs < rhs})

5、参数名称缩写
如果你熟悉shell或者一些脚本语言,那么你肯定知道其中$0代表第一个变量,$1代表第二个变量
在swift的闭包表达式中也是如此
swift中用$0表示第一个变量 $n表示第n个变量
这里$0代表上述的lhs,$1代表rhs
所以,干脆连参数表达式和in我们也省略了
sort(&array,{$0 < $1})

6、运算符函数
和C++的运算符重载类似,因为swift本身支持模板,所以运算符本身也是一个函数
由于<运算符支持(Int,Int)->Bool,所以上述可以更加简写为
sort(&array,<)

二、闭包表达式尾随
一中的例子闭包比较简单,所以我们一步步简化。当闭包的表达式比较复杂的时候怎么办呢?
当闭包作为参数中的最后一个参数时,闭包表达式可以用尾随的方式
上边的例子可以改为
sort(&array){$0 < $1}

当只有闭包一个参数的时候,()可以省略
onlyOne{
   //闭包表达式定义
}
这里,我举个实例,帮助大家复习之前学过的内容,顺便更加深入的理解闭包
class CSND{  lazy var myname = "hwc"  func myprint(method:(input:String)->()){    method(input:"hello")  }}var object = CSND()object.myprint{  var result = $0 + " hwc"  println(result)}
这里myprint的参数唯一,并且只是一个函数类型,所以我们可以传入闭包表达式
由于只有一个闭包参数,所以调用的时候省略了()
我这里闭包的定义为,输出myname + " hwc",并且打印
看到这里,不难看出,当闭包作为参数的时候,实际上给用户提供了一个接口,我定义好我规则里的东西,就像我告诉你早上九点上班,晚上六点下班,这是规则里的事情,而晚上六点到早上九点就是我暴露给你的接口,你想干嘛我不管


三、闭包捕获值
就是闭包可以捕获上下文的变量和常量,典型的例子是嵌套函数
func method(){   var temp = 10   func addOne(){temp = temp + 1    }   addOne()   addOne()   println(temp)}
可以看到最后打印的值是12,也就是说,每次捕获到addOne函数中的temp是引用,而不是副本
在举个例子

func CreateMethod()->(Int)->(Int){    var result = 0    func toReturnMethod(input:Int)->(Int){      result = result + input      return result    }}
函数CreateMethod创造一个函数,(Int)->(Int)

这个函数捕获result,然后加上input,后返回
我们如下使用
var function = CreateMethod()var result = function(input:10)result = function(input:10)result = function(input:10)

最后result = 30

说明swift仍然替我们保存了我们想要的那个局部变量result


四、闭包和函数类型都是引用
func CreateMethod()->(Int)->(Int){    var result = 0    func toReturnMethod(input:Int)->(Int){      return result + 5    }    return  toReturnMethod}

var function1 = CrethodMethod()var function2 = function1


//这里 function1和function2都是闭包类型,他们指向同一块内存


五、GCD与UIView实例

UIView.animateWithDuration(1.0,animations:{  //动作},completion:{status in   //status代表动作是否成功  //动作结束后的执行})也可以这么写UIView.animateWithDuration(1.0,animations:{  //动作}){status in   //status代表动作是否成功  //动作结束后的执行}

或者干脆用$0来代表是否成功,不过,个人不太喜欢这种写法


GCD的例子太多了,用之前写过的单例作为例子

关于swift中GCD的的使用,会在下周更新教程

class hwcSingleton {     var testVariable:Int!     func print(){testVariable = testVariable + 1println(testVariable)}    class var sharedObject: hwcSingleton {        struct StaticStruct {            static var predicate : dispatch_once_t = 0            static var instance : hwcSingleton? = nil        }        dispatch_once(&StaticStruct.predicate) {            StaticStruct.instance = hwcSingleton()   StaticStruct.instance?.testVariable = 10        }        return StaticStruct.instance!    }}
g

17 0
原创粉丝点击