Swift闭包

闭包是自包含的函数代码块,可以在代码中被传递和使用。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--