0Pricing
Swift Academy · Lezione

Chiusure

Chiusure

Chiusure è una lezione Swift Academy gratuita su CoddyKit. Questa è la lezione 1 di 1. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Swift Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Swift Academy include 1 lezioni in totale.

Introduzione

Salve,

Le closure sono blocchi di codice autonomi. Una closure viene passata come parametro al codice oppure può essere utilizzata all'interno del codice.

Una closure è un tipo di funzione. Può essere utilizzata passandola al codice. Le closure sono simili alle lambda di altri linguaggi di programmazione.

Gestione della memoria

Uno degli aspetti più importanti è che una closure può memorizzare i valori delle costanti e delle variabili nell'ambito in cui è definita.

Questa memorizzazione è nota come closing-over.

Swift gestisce per noi la memoria durante questa memorizzazione.

Tipi di closure

Esistono diversi tipi di closure.

  1. Le funzioni globali sono closure con nome. Queste funzioni non conservano alcun valore.
  2. Le funzioni annidate possono contenere i valori del nome e della funzione che le racchiude.
  3. Le espressioni di closure, invece, sono closure anonime e possono memorizzare i dati del contesto circostante usando una sintassi semplice.

Sintassi delle closure

La sintassi delle closure è stata semplificata il più possibile. Tra gli aspetti più importanti ci sono i seguenti.

  • I parametri nelle closure possono essere dedotti.
  • I valori restituiti possono essere dedotti.
  • Il valore restituito dalla closure può essere espresso su una sola riga.
  • I nomi degli argomenti possono essere espressi usando abbreviazioni come $ 0 o $ 1.
  • È possibile usare la sintassi trailing closure.

Informazioni

Le espressioni di closure indicano la scrittura delle closure inline, privilegiando sintassi e semplicità.

Sintassi della closure

La sintassi di una closure è mostrata nel codice di esempio seguente.

{ (parameters) -> return type in
    statements
}


func backward(_ s1: String, _ s2: String) -> Bool {
    return s1 > s2
}
//If we didn't use closures, our code structure would be as follows.

var reversedNames = names.sorted(by: backward)

Sintassi della closure

Tuttavia, con una closure non è necessario definire una closure globale con nome di questo tipo, assegnandole un nome superfluo.

È sufficiente definire una semplice espressione di closure nel parametro. Diamo un'occhiata all'esempio.

let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
let reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
    return s1 > s2
})

print(reversedNames)

///sorted method takes closure as parameter.

Parola chiave in

Dalla parola chiave in si capisce che inizia il corpo della closure.

Prima di iniziare la parola chiave in, è necessario definire i parametri ricevuti dalla closure e il tipo restituito.

Deduzione del tipo dal contesto

Deduzione dei tipi dal contesto

Nell'esempio precedente, l'espressione di closure può essere compresa deducendo i parametri e il tipo restituito, poiché il metodo sorted riceve una closure.

Pertanto, non è necessario definirli esplicitamente.

Poiché i valori nell'array names sono String, si deduce che i parametri ricevuti dalla closure saranno di tipo String.

Allo stesso modo, la closure in questione deve restituire un valore Bool per l'ordinamento, quindi il tipo restituito sarà dedotto come Bool.

Esempio

Questo semplifica l'utilizzo come segue.

La freccia può inoltre essere omessa dal codice deducendo il tipo restituito.

let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
let reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in
    return s1 > s2
})

print(reversedNames)

Sintassi abbreviata

Per evitare di confondere i lettori del codice, è preferibile usare la sintassi estesa invece di quella abbreviata.

La sintassi precedente può essere ulteriormente abbreviata.

Il valore restituito può essere abbreviato con l'espressione di closure rimuovendo la parola chiave return.

/*
In this example, the return keyword has been extracted.
It already has single expression. 
There is no need to express it as an extra with return.
*/

var names = ["Coddy", "Kit"]
let reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )
print(reversedNames)

Esempio

In questo esempio, la parola chiave return è stata omessa.

È già presente una singola espressione e non è necessario indicarla esplicitamente con return.

reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } )

Abbreviazione del nome

La sintassi può essere ulteriormente abbreviata. Nell'esempio precedente abbiamo indicato che la closure accetta due parametri, inclusi s1 e s2. I relativi tipi vengono dedotti.

Ora possiamo evitare di specificare questi parametri e i relativi tipi usando le abbreviazioni.

Inoltre, poiché non è necessario definire i parametri né specificare il valore restituito, si può omettere anche la parola chiave in.

let names = ["Coddy", "Kit"]
let reversedNames = names.sorted(by: { $0 > $1 } )
print(reversedNames)

// In this example $0 will shortcut the first parameter and $1 will shortcut the second parameter.

Esempio abbreviato

var names = ["Coddy", "Kit"]

let reversedNames = names.sorted(by: >)
print(reversedNames)
// Greater than operator takes two parameters and the rotation type is squat.

TRAILING CLOSURE

Trailing Closure

Se il parametro da passare a una funzione closure è l'ultimo argomento della funzione e l'espressione di closure è lunga, può essere più utile scriverla usando la sintassi trailing closure.

È possibile usare trailing closure come zucchero sintattico. Serve ad aumentare la leggibilità del codice.

L'ultimo parametro della maggior parte dei metodi iOS è una closure.

Parametro finale

Ad esempio, in questo esempio, il parametro finale è una closure.

class Animator {
    class func animate(withDuration duration: Double, animations: () -> Void) {
        animations()
    }
}

class MyViewController {
    func start() {
        // With the traditional method, we can call this fund as follows.
        Animator.animate(withDuration: 1, animations: { [unowned self] in
            print("red")
        })
    }
}
MyViewController().start()

Poiché il codice precedente è meno leggibile, può essere scritto come segue

Poiché il codice precedente è meno leggibile, può essere scritto come segue.

import Foundation
Thread.sleep(forTimeInterval: 1)
print("Background color changed to red")

Esempio

Quando si usa la sintassi trailing closure, non è necessario scrivere l'etichetta dell'argomento.

Questo perché le closure sono ormai diventate parte della chiamata della funzione.

func someFunctionThatTakesAClosure(closure: () -> Void) {
    // function body goes here
}

// Here's how you call this function without using a trailing closure:
someFunctionThatTakesAClosure(closure: {
    // closure's body goes here
})

// Here's how you call this function with a trailing closure instead:
someFunctionThatTakesAClosure() {
    // trailing closure's body goes here
}

Sintassi

In realtà possiamo considerare la sintassi trailing closure uno zucchero sintattico. Rende il codice più leggibile.

/*
In the example below, animations
are expressed as closure.
*/
public class func animate(withDuration: TimeInterval, animations: () -> Void)

// In traditional usage, we need to make a call like the following.
UIView.animate(withDuration: 1, animations: { [unowned self] in
    self.view.backgroundColor = UIColor.red
})

/*
In this way, both the readability of the code
increases and we avoid the use of extra brackets.
If it is as above and the last parameter of the method 
is closure, Swift allows to make a call like the one below.
*/

UIView.animate(withDuration: 1) { [unowned self] in
    self.view.backgroundColor = UIColor.red
}

È possibile usare il codice seguente per testare il codice

È possibile usare il codice seguente per testare il codice.


func greetThenRunClosure(name: String, closure: () -> ()) {
    print("Hello, \(name)!")
    closure()
}

greetThenRunClosure(name: "Paul") {
    print("The closure was run")
}

Cattura dei valori da parte delle closure

Cattura dei valori da parte delle closure

Una closure può conservare il valore delle variabili che racchiudono il suo ambiente. È persino possibile modificare i valori di queste variabili dall'interno del proprio corpo e accedervi.

Anche se non si trovano nell'ambito originale in cui queste variabili sono state definite.

Continua

In generale, i dati possono essere conservati nelle funzioni annidate e nelle espressioni di closure. Queste possono memorizzare i dati della funzione esterna.

func makeIncrementer(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementer() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementer
}

let incrementByTen = makeIncrementer(forIncrement: 10)

print(incrementByTen())
// returns a value of 10
print(incrementByTen())
// returns a value of 20
print(incrementByTen())
// returns a value of 30

Continuazione

Se si assegna una closure come proprietà di una classe, questa inizierà a mantenere i riferimenti a questa istanza.

Pertanto, tra closure e istanza si creerà un ciclo di riferimenti forti.

È necessario prestare particolare attenzione alle perdite di memoria.

Avvertenza

Le closure e le funzioni sono tipi di riferimento.

@escaping

Potrebbe essere necessario usare questa sintassi in molti punti in cui la closure viene usata in modo asincrono.

Nelle prime versioni di Swift (1 e 2), le closure nei parametri Swift erano escaping e in seguito sono diventate non-escaping. Se era necessario passare la closure come non-escaping, era necessario specificarlo esplicitamente.

Nelle versioni successive, i parametri closure sono diventati non-escaping per ottenere un vantaggio in termini di utilizzo della memoria.

Ora, se si desidera definire una closure come escaping, è necessario specificarlo con la parola chiave @escaping.

@ESCAPING: parola chiave

@ESCAPING: parola chiave

Se desideriamo poter chiamare le closure assegnate a una funzione dopo che la funzione ha restituito il controllo, dobbiamo indicarle con la parola chiave @escaping.

Le closure definite per impostazione predefinita come parametri di una funzione sono tipi di riferimento, ma non incrementano il conteggio dei riferimenti. Poiché, al momento della chiamata, la durata di questa closure termina, non è necessario aumentare ulteriormente il conteggio dei riferimenti.

Tuttavia, se è necessario usare la closure passata come parametro dopo la chiamata di una funzione, potrebbe essere necessario indicarla con la parola chiave @escaping.

nonEscaping

Per prima cosa, vediamo come funziona una closure non-escaping.

Quando questa closure viene passata come parametro alla funzione, viene elaborata nel corpo della funzione e poi restituita al compilatore.

Dopo la restituzione della funzione, ovvero al termine dell'esecuzione, esce dall'ambito della closure e viene rimossa dalla memoria.

Uso delle closure escaping

Uso delle closure escaping

Quando una closure viene passata come argomento, continua a essere mantenuta anche dopo che la funzione che la contiene restituisce il controllo e l'esecuzione è completata.

Occupa spazio in memoria fino a quando la closure non viene eseguita. Esistono diversi tipi di closure escaping.

Congratulazioni

Congratulazioni 🎉

Siamo giunti al termine della lezione. 

Ci vediamo nella prossima lezione 😎

Chiusure — illustrazione 29

Domande Frequenti

La lezione «Chiusure» è gratuita?

Sì — il testo completo di «Chiusure» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Swift Academy, passa a CoddyKit PRO. Il corso Swift Academy include 1 lezioni in totale.

Cosa imparerò in «Chiusure»?

Chiusure Eserciti Swift Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Swift Academy?

Non è richiesta alcuna esperienza precedente. Swift Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 1 di 1.

Quanto tempo richiede la lezione «Chiusure»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Swift Academy?

Sì. Ogni lezione Swift Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

← Torna a Swift Academy