将闭包传递给函数

函数可以接受闭包(或其他函数)作为参数:

func foo(value: Double, block: () -> Void) { ... }
func foo(value: Double, block: Int -> Int) { ... }
func foo(value: Double, block: (Int, Int) -> String) { ... }

尾随闭包语法

如果函数的最后一个参数是闭包,则可以在函数调用之后写入闭包括号 { / }

foo(3.5, block: { print("Hello") })

foo(3.5) { print("Hello") }

dispatch_async(dispatch_get_main_queue(), {
    print("Hello from the main queue")
})

dispatch_async(dispatch_get_main_queue()) {
    print("Hello from the main queue")
}

如果函数的唯一参数是闭包,则在使用尾随闭包语法调用它时,也可以省略一对括号 ()

func bar(block: () -> Void) { ... }

bar() { print("Hello") }

bar { print("Hello") }

@noescape 参数

标记为 @noescape 的闭包参数保证在函数调用返回之前执行,因此在闭包体内不需要使用 self.

func executeNow(@noescape block: () -> Void) {
    // Since `block` is @noescape, it's illegal to store it to an external variable.
    // We can only call it right here.
    block()
}

func executeLater(block: () -> Void) {
    dispatch_async(dispatch_get_main_queue()) {
        // Some time in the future...
        block()
    }
}
class MyClass {
    var x = 0
    func showExamples() {
        // error: reference to property 'x' in closure requires explicit 'self.' to make capture semantics explicit
        executeLater { x = 1 }

        executeLater { self.x = 2 }  // ok, the closure explicitly captures self

        // Here "self." is not required, because executeNow() takes a @noescape block.
        executeNow { x = 3 }

        // Again, self. is not required, because map() uses @noescape.
        [1, 2, 3].map { $0 + x }
    }
}

Swift 3 注:

请注意,在 Swift 3 中,你不再将块标记为 @noescape。现在,块默认情况下不会转义。在 Swift 3 中,不是将闭包标记为非转义,而是使用“@escaping”关键字标记一个转义闭包的函数参数。

throwsrethrows

与其他函数一样,闭包可能会抛出错误

func executeNowOrIgnoreError(block: () throws -> Void) {
    do {
        try block()
    } catch {
        print("error: \(error)")
    }
}

当然,该函数可以将错误传递给其调用者:

func executeNowOrThrow(block: () throws -> Void) throws {
    try block()
}

但是,如果传入的块没有抛出,则调用者仍然使用 throw 函数:

// It's annoying that this requires "try", because "print()" can't throw!
try executeNowOrThrow { print("Just printing, no errors here!") }

解决方案是 rethrows ,它指定函数只能在其闭包参数抛出时抛出

func executeNowOrRethrow(block: () throws -> Void) rethrows {
    try block()
}

// "try" is not required here, because the block can't throw an error.
executeNowOrRethrow { print("No errors are thrown from this closure") }

// This block can throw an error, so "try" is required.
try executeNowOrRethrow { throw MyError.Example }

许多标准库函数使用 rethrows,包括 map()filter()indexOf()