Swift fa parte di una categoria di linguaggi chiamati ad oggetti, i quali a loro volta prendono il nome dal paradigma a cui sono ispirati: Object Oriented programming o OOP.

Non farti spaventare dagli acronimi.

Come esistono lingue a discendenza neolatina o anglosassone, lo stesso vale per i linguaggi di programmazione.

Il paradigma OOP si basa sul concetto di oggetti. Un oggetto è un contenitore di data (informazioni) e behaviour (comportamento). Per esempio, Text o Image che abbiamo incontrato nel modulo scorso, sono oggetti che ci permettono di rappresentare testi ed immagini sotto forma di codice.

Ovviamente non basta conoscere solamente quali oggetti utilizzare per poter scrivere un programma o applicazione. Sapere che esiste Text non è di gran aiuto se non sai come usarlo o dove metterlo.

Ed è qui che entrano in gioco conoscere la grammatica e sintassi di un linguaggio.

Grazie alla grammatica, cioè le regole da seguire per comporre delle istruzioni valide, sarai in grado di prendere oggetti da una libreria come SwiftUI e comporli senza dover necessariamente seguire un tutorial.

In questa lezione del corso SwiftUI Tour esploreremo alcuni concetti di programmazione che formano la base di qualsiasi linguaggio ad oggetti come Swift, Kotlin, C#, Typescript etc.

Cominceremo dal capire la differenza tra Type and Object, vedremo i type fondamentali del framework Foundation (tra i quali String, Int, Double, Bool) ed infine impareremo ad utilizzare le var e let.

Let's start!

Type vs Object

Un Type è il blueprint di un oggetto. Ne definisce il comportamento, le funzioni o metodi con cui potrai interagirci e la tipologia d'informazioni che trasporterà.

Possiamo considerare i type o tipi di dato come la fabbrica da cui provengono i nostri oggetti.

In genere i Type definiscono tre aspetti di un oggetto:

  1. Creazione: definisce i metodi da utilizzare per creare un oggetto e quali parametri, se richiesti, dovrai utilizzare.

    1. Di questa categoria fa parte la keyword init.

  2. Interazione: definisce quali metodi o funzioni potrai utilizzare per modificare o interagire con l'oggetto creato.

    1. func è la keyword che ci permetterà di definire il comportamento di un oggetto.

  3. Introspezione: definisce delle proprietà che potrai leggere per analizzare il contenuto dell'oggetto.

    1. var e let sono le keywords che ci aiuteranno ad accedere e conservare il contenuto di un oggetto.

Se prendiamo come esempio il type Text abbiamo visto che è una View in grado di renderizzare graficamente dei testi o String. Si costruisce passando tra le parentesi tonde un testo virgolettato Text("ciao"). E può essere modificato utilizzando i modifiers come font e fontWeight :

Text("ciao") // creiamo un oggetto Text con contenuto "ciao"
  .font(.title1) // modifichiamo l'oggetto cambiando il font

Text("come stai?") // creazione
  .fontWeight(.bold) // interazione

Un oggetto viene anche detto istanza o rappresentazione reale di un Type. Nell'esempio diremo che il Text("ciao") è un oggetto di type Text.

Ma da dove vengono questi Type?

Di base il linguaggio di programmazione Swift porta con se diverse librerie di Type. Una tra queste si chiama Foundation e potrai utilizzarla, come il nome suggerisce, per creare le fondamenta della tua app.

Se ti ricordi dal modulo precedente, tutti i file in cui abbiamo definito le nostre interfacce cominciamo con un import SwiftUI.

Ed infatti anche SwiftUI è una libreria o SDK (Software Development Kit). E contiene tutte le definizioni o type necessari a creare User Interfaces in Swift:

Grazie all'import potrai utilizzare tutti i Type pubblici presenti all'interno di una libreria.

Da qui in avanti vedrai che esistono tanti SDK ed ognuno di loro è stato creato per risolvere diversi problemi. Per esempio MapKit fornisce tutti i type essenziali per interagire con le mappe di sistema.

Per la stragrande maggioranza del corso SwiftUI Tour ci focalizzeremo sui type della libreria o framework Foundation ed SwiftUI.

Cominciamo dando uno sguardo a Foundation.

I Type del Foundation framework

Foundation è il framework che rappresenta la spina dorsale di qualsiasi progetto scritto con il linguaggio Swift.
All'interno del Foundation framework troviamo type essenziali come numeri, testi, collezioni di elementi e type per interagire con servizi di sistema come il calendario ed URL.

Fermiamoci qua con la teoria e passiamo ad un po' di pratica. Comincia aprendo il Playground.

ℹ️ Sei incappato in questa lezione per sbaglio? ho spiegato come si crea un Playground qui. Inoltre, se stai imparando a sviluppare app per iOS, qui trovi tutte le lezioni del corso SwiftUI Tour.

String

Il type String descrive testi ed operazioni su testi. Un oggetto di tipo String viene creato in due modi:

  1. Esplicitamente: Scrivendo il nome del type, le parentesi ed il contenuto: String("contenuto")

  2. Implicitamente: Utilizzando solamente le doppie virgolette.

String("ciao") // Esplicito
String() // Esplicito
"come stai?" // Implicito

Nell'esempio possiamo notare come String() genera un testo vuoto o equivalente a scrivere "".

Int e Double

Il type Int rappresenta numeri interi positivi o negativi. Mentre il type Double numeri con virgola.

Come per le String, anche un Int e Double può essere creato esplicitamente o implicitamente:

Int() // 0
Int(10) // Int
-5 // Int

3.0 // Double
Double() // 0.0
Double(-4) // Double
Double(25.0) // Double

Alcune importanti considerazioni:

  • Int() e Double() generano valori uguali a 0.

  • Le virgole si scrivono utilizzando la notazione anglosassone .. Le migliaia non hanno bisogno di ,.

  • Un Int è sempre positivo a meno che non aggiungi il - davanti al numero.

  • Anche se il Double ha valore 0 dopo la virgola, verrà comunque considerato come oggetto di tipo Double.

  • Quando definisci numeri in maniera implicita, in base alla presenza o meno della virgola il sistema deciderà se il type è Int o Double.

Bool

Un Bool è un valore che può essere o true o false. Viene principalmente utilizzato per rappresentare il risultato di espressioni che possono biforcarsi in base a delle condizioni aritmetiche.

Anche questo può essere definito in maniera esplicita ed implicita.

Bool() // false
Bool(false)
Bool(true)

true
false
  • Di default un oggetto Bool() viene considerato false.

Uguaglianza e comparazione

Adesso che abbiamo aggiungo un po' di foundation Type nel nostro repertorio, vediamo alcune operazioni che potremo eseguire tra loro.

Tutte le operazioni di eguaglianza generano un oggetto di tipo Bool che sarà true o false in base ai valori comparati. Le operazioni si eseguono con i seguenti simboli:

  • == uguale

  • != diverso

  • > o >= maggiore o maggiore ed uguale

  • < o <= minore o minore ed uguale

Vediamo un esempio utilizzando numeri:

2 > 3 // false
2 != 2 // false
2 == 2 // true
2.5 < 5.0 // true

10 >= 10 // true
10 <= 10.1 // true

Le operazioni si leggono da sinistra verso destra. Per esempio: 2 > 3 puoi leggerla come è 2 maggiore di 3?, il risultato è true.

Anche gli oggetti di tipo String possono essere comparati. Ma, a differenza dei numeri, possono ritornare risultati inaspettati. Vediamo qualche esempio:

"a" == "a" // true
"b" != "a" // true

"hello" == "ciao" // false
"peppe" != "luca" // true

"giuseppe" == "Giuseppe" // false
"PEPPE" == "peppe" // false

Nel caso di "PEPPE" == "peppe" la logica ci dice che sono entrambi uguali ma Swift ci risponde con false.

Per il linguaggio Swift tutte le operazioni tra String some type sensitive. Minuscole e maiuscole vengono considerati come valori diversi pur rappresentando logicamente lo stesso carattere.

Per quanto riguarda la comparazione, anche qui ci sono alcuni casi da prestare attenzione:

"a" > "b" // false
"b" < "c" // true

"ab" > "c" // false

Nel caso di maggioranza e minoranza le stringhe vengono comparate carattere per carattere. Nell'esempio sopra "ab" > "c" il risultato è false perché il primo carattere sulla sinistra, ovvero a, è minore del primo carattere sulla destra: c.

Se sei confuso è normale, ti servirà un po' di tempo e pratica per comprendere le eguaglianze di String. Nella prossima lezione troverai degli esercizi che ti aiuteranno a fissare questi argomenti.

Infine, anche i tipi booleani possono essere comparati.

true == true // true
false != false // false

Type safety

Swift oltre ad essere un linguaggio ad oggetti è anche un linguaggio Type Safe. Ovvero operazioni tra oggetti di tipo eterogeneo sono controllate ed eventualmente considerate errori a compile-time.

Cosa significa?

I Type oltre a descrivere behaviour e data di un oggetto, definiscono anche quali operazioni sono possibili con oggetti di type diverso.

Per esempio, è considerato un errore sommare String con Int:

"2" + 1 // Binary operator '+' cannot be applied to String and Int
Binary operator '+' cannot be applied to String and Int

Anche sommare Int con Double è considerato errore. Infatti, il linguaggio Swift non sa quale type restituire come risultato dell'operazione:

Int(2) + Double(2.5)
Binary operator '+' cannot be applied to operands of type 'Int' and 'Double'

Essere un linguaggio type safe significa anche che ogni operazione restituirà un Type definito nel momento in cui scriviamo il nostro codice.
In questo caso, abbiamo un Int + Double che confonde Swift dato che non sa quale type scegliere come risultato.

Quindi come risolviamo questi problemi?

Il alcuni casi sarà impossibile, in altri ci sono compressi.

Nel caso di Int + Double dobbiamo decidere di convertire uno dei due oggetti nell'altro. Se convertiamo il Double ad Int perderemo il valore dopo la virgola, quindi in base al contesto deciderai se conviene convertire Int a Double o viceversa:

Int(2) + Int(2.5) // 4
Double(2) + Double(2.5) // 4.5

Lo stesso vale per le String, possiamo convertire Int e Double in modo tale da permettere la somma tra due stringhe:

"1" + String(2) // "12"

Type safety ci aiuta a scrivere codice in maniera sicura, da qui la parola "safety". Infatti, come abbiamo, visto non servirà nemmeno lanciare l'app sul simulatore per capire se abbiamo scritto operazioni tra type non permessi.

Ad ogni modo, type safety non è una proprietà confinata alle operazioni. Vedremo più avanti che utilizzeremo questo termine per definire funzioni, nuovi type e data storage.

Esercizio

Perché la seguente operazione è permessa?

2 + 2.5 // 4.5

Tip: ricordati che alcuni Type vengono definiti in maniera implicita.

init e come si costruiscono gli oggetti in Swift

Per poter creare un oggetto possiamo utilizzare quattro metodi messi a disposizione del linguaggio Swift:

  1. Utilizzando la keyword init subito dopo il nome di un Type. La sintassi è Type.init() dove all'interno delle parentesi tonde, in base alle specifiche del type in questione, potrai inserire dei parametri o argomenti.

    1. init significa initialiser o costruttore.

  2. Scrivendo Type() dove all'interno delle tonde, se richiesto, inserirai i parametri di inizializzazione.

  3. Scrivendo Type { } dove all'interno delle graffe scriveremo un'espressione/codice che verrà valutata in base al contesto. Un esempio è VStack { Text("hello") }, spiegheremo un po' meglio questo tipo di costruttori quando imparerai ad usare le funzioni in Swift.

  4. Utilizzando uno degli oggetti di base o standard di un type utilizzando la sintassi Type.objectName dove objectName dipenderà dal Type in questione.

    1. Per esempio se scrivi Int.max stai costruendo un oggetto Int con il massimo valore rappresentabile.

Userò la parola "argomenti" in maniera intercambiabile con "parametri". In genere, sono i valori che si inseriscono all'interno delle parentesi tonde di un init o func.

Durante il modulo scorso e questa lezione hai già costruito parecchi oggetti, adesso stiamo solamente formalizzando la sintassi ed operazione. In questo modo quando incontrerai un Type() o Type.init sai che si tratta di un'inizializzazione di un oggetto.

Un modo veloce per capire come si costruisce un oggetto è quello di farsi aiutare da Xcode, infatti se scrivi Type.init dovrebbe comparire la lista di tutti i costruttori disponibili.

Proviamo un esempio con Text, all'interno del playground aggiungi import SwiftUI e poi scrivi Text.init, dovresti vedere una lista di operazioni permesse:

Se guardiamo il primo init(_ content: StringProtocol) ci sta dicendo che possiamo inizializzare un oggetto passando all'interno delle parentesi tonde un oggetto di type StringProtocol.

Nelle lezioni precedenti abbiamo utilizzato implicitamente il primo costruttore che accetta un content di type StringProtocol.

String fa parte della famiglia di type StringProtocol, quindi ti è permesso scrivere:

Text("ciao")
Text.init("ciao")

// oppure
Text(String("ciao"))
Text.init(String.init("ciao"))

Capiremo meglio cos'è un Protocol in una lezione tutta dedicata all'argomento.

Eccezione alla regola

Int, Double, String ed altri type fondamentali del linguaggio Swift sono casi eccezionali perché si possono creare scrivendo direttamente il valore, esempio 3 è equivalente a scrivere Int.init(3) o Int(3).

Vedremo che esisteranno altri due casi come questi che ci permetteranno di definire liste e matrici di oggetti, ma aldilà di questi casi eccezionali, tutti gli oggetti si creano con init, parentesi tonde o graffe.

Analisi di un init

Analizzare gli init ed i suoi argomenti ti aiuta a capire come comporre il tuo codice anche senza necessariamente conoscere tutti gli oggetti di un framework.

Per esempio, prendiamo in analisi il costruttore .init(_ date: Date, style: Text.DateStyle) anche se non sappiamo cosa siano Date e Date.DateStyle sappiamo che potremmo costruire un Text passando un oggetto Date ed un oggetto DateStyle:

Possiamo avventurarci nella costruzione di questi due oggetti utilizzando uno dei quattro metodi visti sopra. Il più semplice è provare Type.init o cercare qualche oggetto di default con Type..

Nel caso di Date usiamo il costruttore vuoto Date() mentre per Text.DateStyle vediamo che ci sono degli oggetti di default e nessun init, prendiamone uno a caso:

import SwiftUI

Text.init(Date.init(), style: Text.DateStyle.date)

Et voilà, anche senza conoscere Date e Text.DateStyle siamo riusciti a costruire un oggetto Text.

Proviamo adesso a visualizzare il contenuto del Text dentro il playground utilizzando la setLiveView vista nella lezione precedente:

import SwiftUI
import PlaygroundSupport

PlaygroundPage.current.setLiveView(
    Text(Date(), style: Text.DateStyle.date)
)

Nota come nell'esempio ho omesso .init. Il motivo? Semplice abitudine e spesso e volentieri in grandi progetti l'init non è esplicitato.

Ed eccoci che capiamo come Date descrive date in un calendario e grazie al Text potremo visualizzarle su schermo:

Date e Text in SwiftUI

Recap

  • Type è il blueprint che descrive in maniera astratta come si costruisce ed interagisce con un oggetto, mentre un oggetto è la rappresentazione reale di quel type.

  • Una libreria o SDK o framework è una collezione di Type che ti facilitano nella creazione di app o features. Per esempio SwiftUI è il framework che contiene tutti i type per creare User Interface. Il framework Foundation offre i type di partenza per tutti i progetti Swift.

    • import NomeFramework importa tutte le definizione dei type all'interno di un file.

  • Gli oggetti si costruiscono utilizzando un init o una serie di parentesi tonde o graffe.

  • Swift è un linguaggio type safe: operazioni ed interazioni tra oggetti sono controllate a compile time (mentre scrivi il codice).

Conclusione

Lo so che la teoria annoia, ma ti assicuro che i concetti affrontati in questa lezione rappresentano la base non solo di Swift e SwiftUI ma di moltissimi altri linguaggio di programmazione ad oggetti come Kotlin, Typescript e C#.

Capire la differenza tra Type ed oggetti è il primo passo per essere considerati junior developer.

Ovviamente, non basterà solo questo ma almeno è un buon inizio.

Un altro importante step, soprattutto quando si è alle prime armi, è quello di imparare ad utilizzare e leggere la documentazione ufficiale. La documentazione ti aiuterà tantissimo nel comprendere nuovi Type e come utilizzarli.

Buona programmazione!