Swift Language Passando le chiusure in funzioni

Esempio

Le funzioni possono accettare chiusure (o altre funzioni) come parametri:

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

Sintassi di chiusura finale

Se l'ultimo parametro di una funzione è una chiusura, le parentesi di chiusura { / } possono essere scritte dopo il richiamo della funzione:

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")
}

Se l'argomento di una funzione è solo una chiusura, puoi anche omettere la coppia di parentesi () quando la si chiama con la sintassi della chiusura finale:

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

bar() { print("Hello") }

bar { print("Hello") }

Parametri @noescape

I parametri di chiusura contrassegnati con @noescape sono garantiti per l'esecuzione prima che la chiamata della funzione ritorni, quindi utilizzando self. non è richiesto all'interno del corpo di chiusura:

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 note:

Nota che in Swift 3 non contrassegni più blocchi come @noescape. I blocchi ora non escaping per impostazione predefinita. In Swift 3, invece di contrassegnare una chiusura come non-escape, contrassegni un parametro di funzione che è una chiusura di escape come escaping usando la parola chiave "@escaping".


throws e rethrows

Le chiusure, come altre funzioni, possono generare errori :

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

La funzione può, naturalmente, passare l'errore al suo chiamante:

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

Tuttavia, se il blocco inoltrato non viene lanciato, il chiamante è ancora bloccato con una funzione di lancio:

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

La soluzione è rethrows , che designa che la funzione può lanciare solo se il suo parametro di chiusura genera :

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 }

Molte funzioni di libreria standard utilizzano i rethrows , inclusi map() , filter() e indexOf() .