Nel tuo viaggio da sviluppatore iOS saranno tante le volte in cui dovrai ripetere operazioni.

Immagina, per esempio, di voler leggere gli elementi di un’array composto da migliaia di elementi. Con gli strumenti che hai visto fino a questo momento è impensabile risolvere questo problema perché significherebbe dover scrivere riga per riga l’accesso agli elementi:

// Esempio: stampa in console tutti gli elementi presenti all'interno di un array:
let array = ["ciao", "come stai?", "hai letto questo messaggio?", "oggi parliamo di ciclo for in Swift"]
array[0]
array[1]
array[2]
// impossibile quando gli elementi sono tantissimi

Ovviamente a tutto c’è una soluzione 😂.

Il linguaggio Swift, infatti, mette a disposizione una keyword che ci permette di ripetere N volte un blocco di codice. Questa istruzione si chiama ciclo for.

Dato che ho già detto tutto, non perdiamo altro tempo e vediamo subito come utilizzare il ciclo for in Swift!

Pronto? cominciamo!

Sintassi del ciclo for-in

Il ciclo for del linguaggio Swift permette di eseguire un blocco di codice in maniera iterativa.

Cosa significa?

Immaginiamo di voler leggere e stampare gli elementi di un’array:

var arrayNomi: [String] = ["giuseppe", "matteo", "luca", "filippo"]

La sintassi di questa istruzione è abbastanza semplice. Bisogna:

  1. Scrivere la keyword for
  2. Aggiungere un simbolo _
    1. si legge underscore e capiremo meglio tra un attimo perché lo stiamo utilizzando
  3. Far seguire la keyword in
  4. Poi aggiungere l’array o, più in generale, la collezione che vogliamo leggere
  5. Ed infine aggiungere un blocco di parentesi graffe

Dovresti avere qualcosa del genere:

var arrayNomi: [String] = ["giuseppe", "matteo", "luca", "filippo"]

for _ in arrayNomi {

}

Cosa dobbiamo mettere all’interno delle parentesi graffe?

Dentro lo scope del ciclo for va inserito il codice che vuoi ripetere. Per il momento, aggiungi un print con una stringa di default:

var arrayNomi: [String] = ["giuseppe", "matteo", "luca", "filippo"]

for _ in arrayNomi {
    print("Ciao")
}

Come si legge tutto questo codice che abbiamo scritto?

La parola for significa ripeti. Ripeti quante volte? Ripeti per N volte quanti sono gli elementi all’interno “in” della collezione definita dopo la keyword in.

Che cosa deve ripetere?

Il blocco di istruzioni messo all’interno delle parentesi graffe.

Quindi, se ti chiedo quante volte troveremo in console la scritta “Ciao”, cosa mi rispondi? 😂

// Ciao
// Ciao
// Ciao
// Ciao

Attenzione al significato di ciclo o iterazione

Il ciclo non viene eseguito tutto in una volta. Come ti ho spiegato in una delle prime lezioni del corso, devi imparare a leggere il codice come se fosse un romanzo.

Il nostro compilatore parte leggendo la keyword for, quindi capisce che deve eseguire delle iterazioni. Legge in e sa che sta camminando all’interno di un array.

Immagina il ciclo come una persona che sta camminando in una via in cui ci sono delle case e da ogni casa ci viene restituito un oggetto, immaginiamo una torta.

Ci sono X case per quanti sono gli elementi degli array. Le case sono ordinate per come si trovano gli elementi della collezione.

Il ciclo for-in passa dalla prima casa, entra e prende il suo valore (la torta), poi torna in macchina e la mangia, cioè esegue le istruzioni all’interno del blocco di codice definito dalle parentesi graffe.

Finito di mangiare la torta, si guarda avanti e vede che ci sono altre case. Quindi, passa alla successiva, prende la torta e la mangia.

Questo significa che, anche se non lo notiamo, passa un po’ di tempo tra un’iterazione e l’altra e sopratutto, lo stato del ciclo, cioè la torta anche se sembra uguale (nel nostro caso stampiamo sempre “Ciao”) in realtà sono entità differenti.

Intercettare i valori iterati

Ti ho detto che il ciclo for in legge e prende i valori dall’array iterato. Questo significa che, ad ogni esecuzione, possiamo utilizzare questo valore intercettato all’interno del blocco di parentesi graffe.

Il valore iterato viene conservato all’interno di una costante e, se vogliamo utilizzarla, dobbiamo specificare l’etichetta (quindi che nome assegnargli) al posto del simbolo underscore:

var arrayNomi: [String] = ["giuseppe", "matteo", "luca", "filippo"]

for nome in arrayNomi {
    print("Ciao", nome)
}

// Ciao giuseppe
// Ciao matteo
// Ciao luca
// Ciao Filippo

Questa costante, che nell’esempio ho chiamato nome, ad ogni iterazione passa al valore successivo all’interno dell’array.

Posizione dell’iteratore all’interno dell’array

Uno degli esercizi più classici per capire il funzionamento, del ciclo for-in del linguaggio Swift, è quello di provare a stampare la posizione della costante iterativa.

Come possiamo fare?

Potremmo utilizzare una variabile Int definita prima che parta il ciclo e poi incrementarla durante l’esecuzione del ciclo.

var arrayNomi: [String] = ["giuseppe", "matteo", "luca", "filippo"]

var index: Int = 0

for nome in arrayNomi {
    print("index: \(index) - value: \(nome)")
    index += 1
}

// index: 0 - value: giuseppe
// index: 1 - value: matteo
// index: 2 - value: luca
// index: 3 - value: filippo

Quindi, prima che finisca il ciclo stiamo incrementando la variabile index di 1 (ti ricordo che quella sintassi è equivalente a index = index + 1) e, di conseguenza, al ciclo successivo la variabile sarà uguale al valore precedentemente calcolato.

In questo modo potremmo anche far a meno di utilizzare la variabile iteratrice e potremmo sfruttare solamente l’index per leggere i valori dell’array:

var index: Int = 0

for _ in arrayNomi {
    print("Ciao", arrayNome[index])
    index += 1
}

Esercizio 1. Cosa succede se la var index invece di partire dal valore 0 parte da 1?

Esercizio 2. Perché ho definito la variabile all’esterno del ciclo e non all’interno?
Prova a spostare l’istruzione var index: Int = 0 all’interno del ciclo e prova a capire cosa succede.

Se non riesci a capire il perché scrivimi pure un commento in fondo alla lezione.

Ciclo for-in e dictionary

Dato che abbiamo studiato, insieme agli array, anche i Dictionary è utilissimo vedere come possiamo sfruttare il ciclo for-in per leggere i suoi valori.

Immaginiamo d’avere un dizionario che rappresenta i salari del personale di un’azienda:

let salaries: [String : Int] = [
    "Giuseppe Sapienza" : 3000,
    "Luca Pappalardo" : 7000,
    "Matteo Laudani" : 5000
]

Il type Tuple

Prima di buttarci dentro il ciclo for, devo fare una piccola digressione per parlarti di un altro tipo di dato che non ho avuto modo di mostrarti durante la lezione dei Type.

Sto parlando del type Tuple.

Una tupla è una lista di valori separati da virgola e racchiusi da parentesi tonde. Sembra simile all’array ma il suo utilizzo è differente. Vediamo la sintassi:

let tuple: (Int, String) = (3000, "Giuseppe Sapienza")

Per leggere i valori della tupla, puoi accedere alle sue proprietà che vengono numerate da zero fino X dove X è l’indice dell’ultimo elemento:

let tuple: (Int, String) = (3000, "Giuseppe Sapienza")
tuple.0 // accedo a 3000
tuple.1 // accedo a Giuseppe Sapienza

Etichette

Dato che è facile confondersi con le Tuple ed i suoi valori, possiamo associare ad ogni posizione un’etichetta. L’etichetta o label va specifica come se fosse una variabile all’interno della tupla stessa. Quindi:

let tuple: (id: Int, name: String) = (3000, "Giuseppe Sapienza")
tuple.id // accedo a 3000
tuple.name // accedo a Giuseppe Sapienza

In questo modo è decisamente più semplice accedere ai valori della tupla.

Le tuple, a differenza degli array, vanno utilizzate per piccole quantità di informazioni che sono accumunate da una logica e che non necessitano della complessità di un array.

Immaginiamo per esempio alle coordinate di un point sullo schermo. Non avrebbe senso utilizzare un array per specificare solamente due valori. Basta creare una tupla e definire le sue label:

let point: (x: Double, y: Double) = (0.5, 90)
print("coordinata x:", point.x)
print("coordinata y:", point.y)

Tuple, for-in e dictionary

Adesso che abbiamo questo nuovo strumento possiamo vedere come utilizzare il ciclo for in per leggere un dizionario.

La sintassi base è la stessa, solamente che cambia il type inferred della costante utilizzata come iteratore. Nel caso dei dizionari, la costante, è esattamente una tupla:

let salaries: [String : Int] = [
    "Giuseppe Sapienza" : 3000,
    "Luca Pappalardo" : 7000,
    "Matteo Laudani" : 5000
]

for user in salaries {
    print(user.key) // key del dict
    print(user.value) // value associata alla key
}

All’interno dello scope potrai accedere alle proprietà:

  1. .key che rappresenta una delle chiavi del dizionario
  2. .value che è il valore associato a quella key.

Questo significa che, all’interno di un ciclo, i valori del dizionario vengono trattati come tuple dove ogni valore è una coppia definita dalla key e dal value associato. Quindi un potremmo considerarlo come un ciclo che itera all’interno di un array di tuple.

Un altro sistema per leggere il dizionario è quello di specificare l’iteratore come se fosse una tupla invece che una singola costante, quindi potrai fare:

for (key, value) in salaries {
    print(key, value)
}

P.S. Ricordati che le etichette dell’iteratore le puoi definire come preferisci. Il consiglio è quello di usare nomi in linea con il contenuto della collezione letta. Importante: dato che l’iteratore conterrà un solo valore della collezione utilizza il singolare (anche nel caso di dizionari conterrà una coppia per ciclo).

Ciclo e dictionary ordinato

Una domanda che sempre mi fate arrivate a questo punto è:

Perché il dizionario viene stampato in un ordine casuale?

I dizionari vengono gestiti in una maniera differente rispetto agli array. Per massimizzarne la loro efficienza, quando si prova ad accedere utilizzando un ciclo, il sistema lo ordina in maniera casuale. In pratica, ogni volta che eseguirai un ciclo, otterrai ordinamenti differenti.

Come posso iterare il dizionario mantenendo l’ordine definito da noi?

Puoi utilizzare la proprietà keys del dictionary che ti restituisce un array di chiavi. Se utilizzi il ciclo for-in su questa proprietà, l’iteratore conterrà la chiave e potrai usare questa key per accedere ai valori del dizionario:

let salaries: [String : Int] = [
    "Giuseppe Sapienza" : 3000,
    "Luca Pappalardo" : 7000,
    "Matteo Laudani" : 5000
]

for key in salaries.keys {
    let salary = salaries[key]
    print(key, salary)
}

Se non dovessi ricordarti il significato della sintassi salaries[key] l’ho spiegata all’interno della lezione dei dizionari.

Break: Il primo control flow

Esistono delle particolari keywords che ti permetteranno di alterare il normale flusso di esecuzione del codice. Queste keywords si chiamano control flow o istruzioni di trasferimento.

La prima che ti mostrerò si chiama break e la sua peculiarità è quella di bloccare l’esecuzione di un ciclo (si usa anche in un altro contesto, ma noi non lo tratteremo in questa lezione).

let messages = ["ciao", "come stai?", "hai letto questo messaggio?", "oggi parliamo di ciclo for in Swift"]

for message in messages {
    print(message)
    break
}

// "ciao"

Perché è stato stampato solo il primo valore?

Come ti dicevo, l’istruzione break, una volta eseguita permette di uscire immediatamente dal ciclo.

Perché è utilissimo il break?

In alcune situazioni può letteralmente far risparmiare un sacco di tempo ed un sacco di risorse alla CPU. Come?

Immagina di voler cercare all’interno di un array un valore e di voler uscire dal ciclo subito dopo averlo trovato. Esempio, ho una lista di contatti unici (nickname o id, pensa ad Instagram) e voglio cercarne uno e non appena lo trovo non ha più senso scorrere l’array:

let followers: [String] = ["xcoding.it", "01ddd.user", "aaa35.surname", "peppe.sapienza", "user.nick1", "aaaa.244"]

let query: String = "peppe.sapienza"
var index: Int = 0

for user in followers {
    print("index: \(index)")
    if (user == query) {
        print("utente trovato: \(user)")
        break
    }
    index += 1
}

Grazie al break gli ultimi due elementi non sono stati iterati e questo significa aver risparmiato due cicli di iterazione. Può sembrare banale ma, in liste con milioni di elementi, utilizzare questo approccio significa cambiare totalmente le prestazioni di un progetto.

Loop e Range definiti

Abbiamo visto che i cicli o loop sono utilissimi per iterare all’interno di collezioni come array e dizionari. Però non vengono sempre usati così, ci sono casi in cui ci serve eseguire delle operazioni in maniera iterativa senza dover dipendere da un array.

Sto riscrivendo il contenuto delle lezioni per seguire il contenuto dei video. Per favore, dato che non ho ancora finito con questa lezione dei cicli for, completala guardando il tutorial.

Esercizi della lezione

  • Esercizio 7. Se “var punteggi = [ 20, 14, 55, 5, 7, 8, 36]” è un array e “var punteggioFinale” è una variabile, implementa un ciclo che sommi tutti i valori dell’array e salvi il risultato nella variabile punteggioFinale.
  • Esercizio 8. Crea un’istruzione di controllo che, date due variabili intere, stampi su schermo “a è maggiore di b” oppure il contrario.
  • Esercizio 9. Creare due array vuoti di interi e inizializzare il primo con valori a scelta. Copiate gli elementi del primo array tramite un ciclo nel secondo array.
  • Esercizio 10. Crea un ciclo for che, dato un’array di interi, stampa solo i numeri maggiori di 10 dell’array.

Buona Programmazione!

Back to: Swift Tour: Corso gratuito linguaggio di programmazione Swift > Swift Tour: Le basi