分类 标签 存档 黑客派 订阅 搜索

Swift 闭包

123 浏览0 评论

闭包是自包含的函数代码块,可以在代码中被传递和使用。Swift 中的闭包与 C 和 Objective-C 中的代码块(blocks)以及其他一些编程语言中的匿名函数比较相似。

闭包可以捕获和存储其所在上下文中任意常量和变量的引用。这就是所谓的闭合并包裹着这些常量和变量,俗称闭包。Swift 会为您管理在捕获过程中涉及到的所有内存操作。

闭包表达式

//sort方法
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]

//普通函数
func backwards(s1: String, s2: String) -> Bool {
    return s1 < s2
}
var reversed = names.sort(backwards)

//闭包表达式语法
reversed = names.sort({(s1: String, s2: String) -> Bool in
    return s1 < s2
})

//根据上下文推断类型
reversed = names.sort({s1, s2 in return s1 < s2})

//单表达式闭包隐式返回
reversed = names.sort({s1, s2 in s1 < s2})

//参数名称缩写
reversed = names.sort({$0 < $1})

//运算符函数
reversed = names.sort(<)

尾随闭包

func someFunctionThatTakesAClosure(closure: () -> Void) {
    //函数体部分
}
//以下是不使用尾随闭包进行函数调用
someFunctionThatTakesAClosure({
    //闭包主体部分
})

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

reversed = names.sort(){$0 < $1} //闭包表达式

reversed = names.sort{$0 < $1} //如果函数表达式只需要一个参数,使用尾随闭包是,可以将 () 省略

//尾随闭包举例
let digitNames = [
    0: "Zero", 1: "One", 2: "Two",   3: "Three", 4: "Four",
    5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
]
let numbers = [16, 58, 510]

let strings = numbers.map {
    (number) -> String in
    var number = number
    var output = ""
    while number > 0 {
        output += digitNames[number % 10]!
        number /= 10
    }
    return output
}

值捕获

func makeIncrementor(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementor() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementor
}
let incrementTen = makeIncrementor(forIncrement: 10)
incrementTen() // 10
incrementTen() // 20
incrementTen() // 30

let incrementBySeven = makeIncrementor(forIncrement: 7)
incrementBySeven() // 7

incrementTen() // 40

闭包是引用类型

let alsoIncrementByTen = incrementTen
alsoIncrementByTen() // 50

非逃逸闭包

func someFunctionWithNoescapeClosure(@noescape closure: () -> Void){
    closure()
}

var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: () -> Void) { //这个时候如果把completionHandler参数标注为 @noescape 会获得一个编译错误
    completionHandlers.append(completionHandler)
}

//将闭包标注为 @noescape 能是你在闭包中饮食调用self
class SomeClass {
    var x = 10
    func doSomething() {
        someFunctionWithEscapingClosure{ self.x = 100 }
        someFunctionWithNoescapeClosure{ x = 200 }
    }
}

let instance = SomeClass()
instance.doSomething()
print(instance.x) // 200

completionHandlers.first?()
print(instance.x) // 100

自动闭包

var customsInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
print(customsInLine.count) // 5

//赋值给一个变量或者常量,实现延时求值
let customerProvider = { customsInLine.removeAtIndex(0) } //只定义,没执行
print(customsInLine.count) // 5

print("No serving \(customerProvider()) !") // prints "Now serving Chris!"
print(customsInLine.count) // prints "4"

//作为函数的参数,实现延时求值
func serverCustomer(customerProvider: () -> String) {
    print("Now serving \(customerProvider())!")
}
serverCustomer({ customsInLine.removeAtIndex(0) }) //prints "Now serving Alex"

func serveCustomer(@autoclosure customerProvider: () -> String) {
    print("Now serving \(customerProvider())!")
}
serveCustomer(customsInLine.removeAtIndex(0))

//@autoclosure特性暗含了@noescape特性,这个特性在非逃逸闭包一节中有描述。如果你想让这个闭包可以“逃逸”,则应该使用@autoclosure(escaping)特性.
var customerProviders: [() -> String] = []
func collectCustomerProviders(@autoclosure(escaping) customerProvider: () -> String) {
    customerProviders.append(customerProvider)
}

print("**Collected \(customerProviders.count) closures.")

collectCustomerProviders(customsInLine.removeAtIndex(0))
collectCustomerProviders(customsInLine.removeAtIndex(0))

print("Collected \(customerProviders.count) closures.")

for customerProvider in customerProviders {
    print("Now serving \(customerProvider())")
}

原文链接

--EOF--

评论  
留下你的脚步
推荐阅读