Swift闭包和函数

2017-01-01 02:19

函数在Swift中只是一种特殊的闭包,闭包在Swift语言中是一等公民,支持闭包嵌套和闭包传递。Swift中的闭包(Closures) 类同于于Objective-C中的代码块(Blocks) ,可以相互参照理解。

函数

//函数语法格式
()->()
定义函数

定义函数需要关键词func, 函数接受和返回的参数可以为0个,一个或多个(返回多个参数可以使用Tuple),且返回时需要使用 ->

//定义函数
func bestWishes(name: String, blessing: String) -> (guest: String, messageOfCongratulation: String) {
    return ("属下, \(name).", "祝教主: \(blessing) ")
}

//调用函数
let retValue = bestWishes(name: "白龙使韦小宝", blessing: "仙福永享,寿与天齐!")
print(retValue)
print(retValue.guest)
print(retValue.messageOfCongratulation)

//把以上代码粘贴到Playground中会输出以下内容:
//("属下, 白龙使韦小宝.", "祝教主: 仙福永享,寿与天齐! ")
//属下, 白龙使韦小宝.
//祝教主: 仙福永享,寿与天齐!
函数类型

每一个函数都有函数类型,该类型由函数自身参数类型和返回类型组成。

//样例
func sum(x: Int, y: Int) -> (result: Int) { return x + y }

上述函数的的类型是:

(Int, Int) -> (Int)

再来一个例子:

//开篇提到的函数
func bestWishes(name: String, blessing: String) -> (guest: String, messageOfCongratulation: String) { 
    return ("属下, \(name).", "祝教主: \(blessing) ")
}

//函数类型
(String, String) -> (String, String)
传递函数和返回函数

我们来实现一个函数可以返回另一个函数,这样返回的函数可以赋值给一个变量并调用它。

func eatPoison () -> ((String, Int) -> String) {
    func posion(name: String, times: Int) -> (String) {
        return "\(name) 服用豹胎易筋丸 \(times) 次"
    }
    return posion
}
let retValue = eatPoison()
print(retValue("韦小宝", 3))
//以上代码粘贴到Playground中会输出以下内容:
//韦小宝 服用豹胎易筋丸 3 次
可变参数函数

可变参数函数指的是函数拥有若干数目不定参数的函数,可以通过类数组类型去访问所有参数。

func poisonRawMaterial (materials: String...) -> () {
    for material in materials {
        print("\(material)")
    }
}
poisonRawMaterial(materials: "豹胎", "鹿胎", "紫河车", "海狗肾")
//以上代码粘贴到Playground中会输出以下内容:
//豹胎
//鹿胎
//紫河车
//海狗肾

闭包

//闭包语法格式
{()->() in}
定义闭包

闭包一般定义在大括号内,闭包由函数类型(闭包头部) 和 关键词 in后的闭包主体组成。

{ (参数) -> 返回类型 in
  闭包主体
}

var clos1 = {
    () -> Void in
    print("第一个闭包")
}

clos1()

通过函数 map可以把操作施加到数组所有元素上。

let murderers = ["胖头陀", "陆高轩", "瘦头陀"]
murderers.map({
    (murderer: String) -> String in
    "\(murderer) 已被洪教主杀死!"
})

注意:上面的闭包没有使用return关键字,因为如果闭包是单行语句闭包,单行语句计算结果会隐式地返回,return关键字可以省略。

Swift可以根据上下文推理参数和返回值类型,这样返回值类型和参数类型可以省略不写。

func applyMutliplication(value: Int, multFunction: (Int) -> Int) -> String{
    return String(multFunction(value))
}

applyMutliplication(value: 4,multFunction: {value in
        value * 5
    })

参数名缩写 - 闭包的参数可以通过位置来访问,如($0,$1, ...)。

applyMutliplication(value: 4,multFunction: {$0 * 5})

尾随闭包 - 而如果闭包是函数的最后一个参数,闭包参数可以写在大括号外。

applyMutliplication(value: 4) {$0 * 5}

关于Swift闭包更多参看官方文档

循环引用

Swift闭包和函数0

在引用计数的系统中,都存在这循环引用的风险,而循环引用可能会导致内存泄漏,这令人不得不防。在定义Swift闭包时同时定义捕获列表作为闭包的一部分,捕获列表定义了闭包体内捕获一个或者多个引用类型的规则。这时使用不当就可能引起循环引用。

跟解决两个类实例间的循环强引用一样,声明被捕获的引用为弱引用**(weak)无主引用**(unowned)就可打破循环引用,至于使用弱引用还是无主引用应当根据上下文来选择。

//延迟加载, 使用unowned打破循环引用。
lazy var printName: ()->() = { [unowned self] in
        print(self.name)
   }

printName是 self 的属性,会被 self 持有,而它本身又在闭包内持有 self,这就存在循环引用的风险,上面例子中用unowned打破了循环,再来使用weak关键词。

lazy var printName: ()->() = { [weak self] in 
    if let strongSelf = self { 
        print("用户名:  \(strongSelf.name)") 
    }
}
Swift闭包和函数1

注意在如何选择使用unownedweak请参考下述规则:

  • 如果捕获的引用绝对不会置为nil,或当闭包和捕获的实例总是互相引用时并且总能同时销毁时,可以将闭包内的捕获定义unowned

  • 当捕获引用有时可能会是nil时,将闭包内的捕获定义为weak。弱引用总是可选类型,并且当引用的实例被销毁后,弱引用的值会自动置为nil,这使我们可以在闭包内检查它们是否存在。

更多请多参看苹果官方文档

推荐阅读Swift 之 非逃逸闭包与逃逸闭包