Swift From Scratch un'introduzione alle classi e alle strutture

Fino ad ora, abbiamo coperto le basi del linguaggio di programmazione Swift. Se hai seguito, dovresti ora avere una solida conoscenza di variabili, costanti, funzioni e chiusure. È giunto il momento di utilizzare ciò che abbiamo appreso e applicare tale conoscenza alle strutture orientate agli oggetti di Swift.

Per comprendere i concetti discussi in questo tutorial, è importante avere una conoscenza di base della programmazione orientata agli oggetti. Se non hai familiarità con classi, oggetti e metodi, ti consiglio di leggere prima questi argomenti prima di continuare con questo tutorial.

eBook: programmazione orientata agli oggetti con Swift

1. Introduzione

In questa lezione, esploreremo gli elementi costitutivi fondamentali della programmazione orientata agli oggetti in Swift, classi e strutture. In Swift, le classi e le strutture si sentono e si comportano in modo molto simile, ma ci sono alcune differenze chiave che è necessario comprendere per evitare le insidie ​​più comuni.

In Objective-C, le classi e le strutture sono molto diverse. Questo non è vero per Swift. In Swift, ad esempio, sia le classi che le strutture possono avere proprietà e metodi. A differenza delle strutture C, le strutture in Swift possono essere estese e possono anche essere conformi ai protocolli.

La domanda ovvia è: "Qual è la differenza tra classi e strutture?" Torneremo su questa domanda più avanti in questo tutorial. Prima esploriamo come appare una classe in Swift.

2. Terminologia

Prima di iniziare a lavorare con classi e strutture, vorrei chiarire alcuni termini comunemente usati nella programmazione orientata agli oggetti. I termini classi, oggetti, e casi spesso confondono le persone nuove nella programmazione orientata agli oggetti. Pertanto, è importante sapere come Swift utilizza questi termini.

Oggetti e istanze

UN classe è un modello o modello per un'istanza di quella classe. Il termine "oggetto" è spesso usato per riferirsi a un'istanza di una classe. In Swift, tuttavia, le classi e le strutture sono molto simili e quindi è più facile e meno confuso usare il termine "istanza" per entrambe le classi e le strutture.

Metodi e funzioni

In precedenza in questa serie, abbiamo lavorato con le funzioni. Nel contesto di classi e strutture, di solito ci riferiamo a funzioni come metodi. In altre parole, i metodi sono funzioni che appartengono a una particolare classe o struttura. Nel contesto di classi e strutture, è possibile utilizzare entrambi i termini in modo intercambiabile poiché ogni metodo è una funzione.

3. Definizione di una classe

Facciamo bagnare i piedi e definiamo una lezione. Accendi Xcode e crea un nuovo parco giochi. Rimuovere il contenuto del parco giochi e aggiungere la seguente definizione di classe.

classe Person 

Il classe parola chiave indica che stiamo definendo una classe chiamata Persona. L'implementazione della classe è racchiusa in un paio di parentesi graffe. Anche se il Persona la classe non è molto utile nella sua forma attuale, è una classe Swift corretta e funzionale.

Proprietà

Come nella maggior parte degli altri linguaggi di programmazione orientati agli oggetti, una classe può avere proprietà e metodi. Nell'esempio aggiornato di seguito, definiamo tre proprietà:

  • nome di battesimo, una proprietà variabile di tipo Stringa?
  • cognome, una proprietà variabile di tipo Stringa?
  • luogo di nascita: una proprietà costante di tipo Stringa
class Person var firstName: String? var lastName: String? let birthPlace = "Belgium"

Come illustra l'esempio, la definizione delle proprietà in una definizione di classe è simile alla definizione di variabili e costanti regolari. Noi usiamo il var parola chiave per definire una proprietà variabile e il permettere parola chiave per definire una proprietà costante.

Le proprietà di cui sopra sono anche conosciute come proprietà memorizzate. Più avanti in questa serie, impariamo a conoscere proprietà calcolate. Come suggerisce il nome, le proprietà memorizzate sono proprietà che vengono archiviate dall'istanza della classe. Sono simili alle proprietà in Objective-C.

È importante notare che ogni proprietà memorizzata deve avere un valore dopo l'inizializzazione o essere definita come un tipo facoltativo. Nell'esempio sopra, diamo il luogo di nascita proprietà un valore iniziale di "Belgio". Questo dice a Swift che la proprietà del luogo di nascita è di tipo Stringa. Più avanti in questo articolo, daremo un'occhiata all'inizializzazione in modo più dettagliato ed esploreremo come si lega all'inizializzazione delle proprietà.

Anche se abbiamo definito il luogo di nascita proprietà come costante, è possibile cambiarne il valore durante l'inizializzazione di a Persona esempio. Una volta che l'istanza è stata inizializzata, il luogo di nascita la proprietà non può più essere modificata poiché abbiamo definito la proprietà come una proprietà costante con permettere parola chiave.

metodi

Possiamo aggiungere un comportamento o una funzionalità a una classe attraverso funzioni o metodi. In molti linguaggi di programmazione, metodo è usato al posto di funzione nel contesto di classi e istanze. La definizione di un metodo è quasi identica alla definizione di una funzione. Nel prossimo esempio, definiamo il nome e cognome() metodo nel Persona classe.

class Person var firstName: String? var lastName: String? let birthPlace = "Belgium" func fullName () -> String var parts: [String] = [] se let firstName = self.firstName parts + = [firstName] se let lastName = self.lastName parts + = [ lastName] return parts.joined (separator: "")

Il metodo nome e cognome() è annidato nella definizione della classe. Non accetta parametri e restituisce a Stringa. L'implementazione del nome e cognome() il metodo è semplice. Attraverso l'associazione opzionale, che abbiamo discusso in precedenza in questa serie, accediamo ai valori memorizzati nel nome di battesimo e cognome proprietà.

Memorizziamo il nome e il cognome del Persona istanza in un array e unire le parti con uno spazio. La ragione di questa implementazione un po 'imbarazzante dovrebbe essere ovvia: il nome e il cognome possono essere vuoti, motivo per cui entrambe le proprietà sono di tipo Stringa?.

la creazione di istanze

Abbiamo definito una classe con alcune proprietà e un metodo. Come creiamo un'istanza di Persona classe? Se hai familiarità con Objective-C, allora amerai la concisione del seguente frammento.

let john = Person ()

Istanziare un'istanza di una classe è molto simile al richiamo di una funzione. Per creare un'istanza, il nome della classe è seguito da una coppia di parentesi e il valore di ritorno è assegnato a una costante o variabile.

Nel nostro esempio, la costante John ora punta a un'istanza di Persona classe. Questo significa che non possiamo cambiare nessuna delle sue proprietà? Il prossimo esempio risponde a questa domanda.

john.firstName = "John" john.lastName = "Doe" john.birthPlace = "Francia"

Possiamo accedere alle proprietà di un'istanza utilizzando la comodità della sintassi del punto. Nell'esempio, abbiamo impostato nome di battesimo a "John", cognome a "Doe", e luogo di nascita a "Francia". Prima di trarre conclusioni basate sull'esempio precedente, dobbiamo verificare eventuali errori nel campo da gioco.

Ambientazione nome di battesimo e cognome non sembra causare problemi. Ma assegnando "Francia" al luogo di nascita la proprietà genera un errore. La spiegazione è semplice.

Nonostante John è dichiarato come una costante, che non ci impedisce di modificare il Persona esempio. C'è un avvertimento, però: solo le proprietà variabili possono essere modificate dopo l'inizializzazione di un'istanza. Le proprietà definite come costanti non possono essere modificate una volta assegnato un valore.

Una proprietà costante può essere modificata durante l'inizializzazione di un'istanza. Mentre il luogo di nascita la proprietà non può essere cambiata una volta a Persona l'istanza è creata, la classe non sarebbe molto utile se potessimo solo istanziare Persona istanze con un luogo di nascita di "Belgio". Facciamo il Persona classe un po 'più flessibile.

Inizializzazione

L'inizializzazione è una fase della durata di un'istanza di una classe o di una struttura. Durante l'inizializzazione, prepariamo l'istanza per l'utilizzo popolando le sue proprietà con i valori iniziali. L'inizializzazione di un'istanza può essere personalizzata implementando un inizializzatore, un tipo speciale di metodo. Definiamo un inizializzatore per il Persona classe.

class Person var firstName: String? var lastName: String? let birthPlace = "Belgium" init () birthPlace = "France" ...

Abbiamo definito un inizializzatore, ma ci imbattiamo in diversi problemi. Dai un'occhiata all'errore che il compilatore ci ha lanciato.

Non solo l'inizializzatore è inutile, il compilatore ci avverte anche che non possiamo modificare il valore di luogo di nascita proprietà poiché ha già un valore iniziale. Possiamo risolvere l'errore rimuovendo il valore iniziale del file luogo di nascita proprietà.

class Person var firstName: String? var lastName: String? let birthPlace: String init () birthPlace = "France" ...

Si noti che il nome dell'inizializzatore, dentro(), non è preceduto dal func parola chiave. A differenza degli inizializzatori in Objective-C, un inizializzatore in Swift non restituisce l'istanza in fase di inizializzazione.

Un altro dettaglio importante è come impostiamo il luogo di nascita proprietà con un valore iniziale. Abbiamo impostato il luogo di nascita proprietà usando il nome della proprietà, ma va anche bene essere più espliciti in questo modo.

init () self.birthPlace = "France"

Il se stesso parola chiave si riferisce all'istanza che viene inizializzata. Ciò significa che self.birthPlace si riferisce a luogo di nascita proprietà dell'istanza. Possiamo omettere se stesso, come nel primo esempio, perché non c'è confusione su quale proprietà ci riferiamo. Questo non è sempre il caso, però. Lascia che ti spieghi cosa intendo.

parametri

L'inizializzatore che abbiamo definito non è molto utile al momento, e non risolve il problema da cui siamo partiti: essere in grado di definire il birthplace di una persona durante l'inizializzazione. 

In molte situazioni, si desidera passare i valori iniziali all'inizializzatore per personalizzare l'istanza che si sta creando. Questo è possibile creando un inizializzatore personalizzato che accetta uno o più argomenti. Nell'esempio seguente, creiamo un inizializzatore personalizzato che accetta un argomento, luogo di nascita, di tipo Stringa.

init (birthPlace: String) self.birthPlace = birthPlace

Vale la pena sottolineare due cose. In primo luogo, ci viene richiesto di accedere a luogo di nascita proprietà attraverso self.birthPlace per evitare ambiguità poiché il nome del parametro locale è uguale a luogo di nascita. In secondo luogo, anche se non abbiamo specificato un nome di parametro esterno, Swift per impostazione predefinita crea un nome di parametro esterno uguale al nome del parametro locale.

Nell'esempio seguente, istanziamo un altro Persona istanza invocando l'inizializzatore personalizzato appena definito.

let maxime = Person (birthPlace: "France") print (maxime.birthPlace)

Passando un valore per il luogo di nascita parametro per l'inizializzatore, possiamo assegnare un valore personalizzato alla costante luogo di nascita proprietà durante l'inizializzazione.

Inizializzatori multipli

Come in Objective-C, una classe o una struttura possono avere più inizializzatori. Nell'esempio seguente, ne creiamo due Persona le istanze. Nella prima riga, usiamo l'inizializzatore di default. Nella seconda riga, utilizziamo l'inizializzatore personalizzato che abbiamo definito in precedenza.

let p1 = Person () let p2 = Person (birthPlace: "France")

4. Definizione di una struttura

Le strutture sono sorprendentemente simili alle classi, ma ci sono alcune differenze chiave. Iniziamo definendo una struttura di base.

struct Wallet var dollars: Int var cents: Int

A prima vista, l'unica differenza è l'uso del struct parola chiave anziché il classe parola chiave. L'esempio mostra anche un approccio alternativo per fornire i valori iniziali alle proprietà. Invece di impostare un valore iniziale per ogni proprietà, possiamo dare alle proprietà un valore iniziale nell'inizializzatore della struttura. Swift non genera un errore, poiché ispeziona anche l'inizializzatore per determinare il valore iniziale e il tipo di ogni proprietà.

5. Classi e strutture

Potresti iniziare a chiedermi quale sia la differenza tra classi e strutture. A prima vista, sembrano identici nella forma e nella funzione, ad eccezione del classe e struct parole chiave. Esistono tuttavia alcune differenze chiave.

Eredità

Le classi supportano l'ereditarietà, mentre le strutture no. Il seguente esempio illustra questo. Il modello di progettazione dell'eredità è indispensabile nella programmazione orientata agli oggetti e, in Swift, è una differenza fondamentale tra classi e strutture.

class Person var firstName: String? var lastName: String? Let birthPlace: String init (birthPlace: String) self.birthPlace = birthPlace Studente: Person var school: String?  let student = Student (birthPlace: "France")

Nell'esempio sopra, il Persona la classe è il genitore o la superclasse del Alunno classe. Ciò significa che il Alunno la classe eredita le proprietà e il comportamento del Persona classe. L'ultima riga illustra questo. Inizializziamo a Alunno istanza richiamando l'inizializzatore personalizzato definito in Persona classe.

Copia e riferimento

Il seguente concetto è probabilmente il concetto più importante in Swift che imparerai oggi, la differenza tra tipi di valore e tipi di riferimento. Le strutture sono tipi di valore, il che significa che vengono passati per valore. Un esempio illustra meglio questo concetto.

struct Point var x: Int var y: Int init (x: Int, y: Int) self.x = x self.y = y var point1 = Punto (x: 0, y: 0) var point2 = point1 point1.x = 10 print (point1.x) // 10 print (point2.x) // 0

Definiamo una struttura, Punto, incapsulare i dati per memorizzare una coordinata in uno spazio bidimensionale. Noi istanziare point1 con X uguale a 0 e y uguale a 0. Noi assegniamo point1 a point2 e impostare il X coordinata di point1 a 10. Se produciamo il X coordinate di entrambi i punti, scopriamo che non sono uguali.

Le strutture vengono passate per valore, mentre le classi vengono passate per riferimento. Se si intende continuare a lavorare con Swift, è necessario comprendere la dichiarazione precedente. Quando abbiamo assegnato point1 a point2, Swift ha creato una copia di point1 e lo ha assegnato a point2. In altre parole, point1 e point2 ogni punto a una diversa istanza del Punto struttura.

Ripetiamo ora questo esercizio con il Persona classe. Nell'esempio seguente, istanziamo a Persona esempio, imposta le sue proprietà, assegna persona1 a Person2, e aggiorna il nome di battesimo proprietà di persona1. Per vedere che cosa passa per riferimento significa per le classi, produciamo il valore di nome di battesimo proprietà di entrambi Persona casi.

var person1 = Persona (birthPlace: "Belgium") person1.firstName = "Jane" person1.lastName = "Doe" var person2 = person1 person1.firstName = Stampa "Janine" (person1.firstName!) // Stampa di Janine (persona2. firstName!) // Janine

L'esempio dimostra che le classi sono tipi di riferimento. Ciò significa che persona1Person2 fare riferimento o riferimento allo stesso Persona esempio. Assegnando persona1Person2, Swift non crea una copia di persona1. Il Person2 variabile punti allo stesso Persona esempio persona1 sta puntando Cambiare il nome di battesimo proprietà di persona1 colpisce anche il nome di battesimo proprietà di Person2, perché si riferiscono allo stesso modo Persona esempio.

Come ho già detto più volte in questo articolo, le classi e le strutture sono molto simili. Ciò che separa classi e strutture è molto importante. Se i concetti di cui sopra non sono chiari, allora ti incoraggio a leggere l'articolo ancora una volta per far affondare i concetti che abbiamo coperto.

Conclusione

In questa puntata di Swift From Scratch, abbiamo iniziato ad esplorare le basi della programmazione orientata agli oggetti in Swift. Classi e strutture sono gli elementi costitutivi fondamentali della maggior parte dei progetti Swift e ne apprenderemo di più nelle prossime lezioni di questa serie.

Nella prossima lezione, continueremo la nostra esplorazione di classi e strutture dando un'occhiata più da vicino alle proprietà e all'eredità.

Se vuoi imparare come usare Swift 3 per codificare le applicazioni del mondo reale, consulta il nostro corso Crea app per iOS con Swift 3. Che tu sia nuovo nello sviluppo di app per iOS o che stia cercando di passare da Objective-C, questo corso ti consentirà di iniziare con Swift per lo sviluppo di app.