Scopri Objective-C Day 4

Benvenuti alla quarta parte di questa serie su Objective-C. Finora, abbiamo analizzato molto la teoria, i principi e la funzionalità del linguaggio per avere una buona idea di come funziona. Oggi faremo una semplice lezione simile all'esempio dell'automobile che abbiamo visto nelle parti precedenti di questa serie. La nostra classe prenderà i dettagli di una macchina, permettendoci di ottenere e impostare i valori detenuti. Dopo l'esempio di oggi dovresti essere in grado di creare le tue classi in Xcode e giocare con loro.

Finora, abbiamo ricevuto ottimi feedback via email, twitter e commenti. È bello vedere così tante persone sono interessate a questo argomento ed è ancora più bello vedere che molti di voi lo stanno provando per te stesso e stanno facendo alcune grandi domande. Continuate così!

Iniziare

Inizia accendendo Xcode e creando un nuovo progetto. Sotto il separatore di Mac OS X, fai clic su Applicazione, quindi fai clic su Strumento riga di comando. Infine, cambia il menu a tendina per impostare il tipo su Foundation.

Salva il progetto come vuoi, ho chiamato il mio CarApp. Una volta visualizzata la finestra del progetto, dobbiamo creare una nuova classe. Premi Comando-N (o File> Nuovo file), vai a Cocoa Class in Mac OS X e seleziona Objective-C class. Assicurati che la sottoclasse di sia impostata su NSObject e premi Avanti. Assegna un nome alla tua classe SimpleCar e assicurati che venga creato un file .h, quindi salvalo.

La nostra classe ora esiste, ma non fa nulla. Cambiamo ciò dandogli del codice. Ricorda che in Objective-C abbiamo diviso il nostro codice in due parti: interfaccia e implementazione. È logico lavorare prima sull'interfaccia, quindi è qui che inizieremo.

Codifica l'interfaccia

Apri il file SimpleCar.h e nel suo stato attuale dovrebbe apparire come questo (ho omesso l'intestazione del commento da sotto)

 #importare  @interface SimpleCar: NSObject  @end 

Prima di tutto, includiamo Cocoa.h, che ci dà accesso a cose come NSString, NSMutableString, ecc. Quindi, creiamo la nostra classe (SimpleCar) come sottoclasse di NSObject.

Ora dobbiamo decidere quali informazioni devono essere archiviate dalla nostra classe. Dal momento che utilizziamo un'auto come esempio, dobbiamo memorizzare le informazioni relative all'auto, come ad esempio:

  • Rendere
  • Modello
  • VIN

C'è molto di più in cui potremmo entrare, ma per ora ciò andrà bene. Per ognuna di queste proprietà, abbiamo bisogno di memorizzarle in una variabile adatta per quel tipo di dati. Creare e modellare sarà un intervallo di caratteri (come testo, numero e eventualmente punteggiatura), quindi è logico utilizzare una stringa. Il VIN (Vehicle Identification Number) sarà solo un numero quindi è quello che useremo. Il nostro codice ora appare come questo (intestazione omessa):

 @interface SimpleCar: NSObject NSString * make; Modello NSString *; NSNumber * vin;  @fine 

In precedenza abbiamo detto che per ottenere o impostare dati da una classe, dovrebbe essere usato un metodo. Quindi per impostare le variabili, dobbiamo aggiungere metodi. Per fare questo, ne faremo quattro: uno imposterà la marca, uno il modello, uno il VIN, e un metodo finale imposterà sia la marca che il modello (solo per mostrarti come usare più argomenti).

 @interface SimpleCar: NSObject NSString * make; Modello NSString *; NSNumber * vin;  // set methods - (void) setVin: (NSNumber *) newVin; - (void) setMake: (NSString *) newMake; - (void) setModel: (NSString *) setModel; // metodo di convenienza - (void) setMake: (NSString *) newMake andModel: (NSString *) newModel; @fine 

Dichiariamo metodi dopo la parentesi graffa e prima di @end. Inserendo un trattino (segno meno) prima del metodo, diciamo al compilatore che stiamo per dichiarare un metodo di istanza. Un metodo di istanza è un metodo eseguito sulla nostra istanza. Viceversa, un segno più indica che il metodo invocato è un metodo di classe che non ha bisogno di una singola istanza di oggetto da eseguire - più su questo più tardi.

Il nostro primo metodo restituisce void, è chiamato setVin e accetta un NSNumber come argomento. Il nostro secondo metodo è simile, restituisce void, è call setMake e prende come argomento un NSString. Il terzo è lo stesso, con un nome diverso.

Il nostro metodo finale restituisce anche void ma prende due parametri: newMake e newModel, entrambi i quali dovrebbero essere NSString. La denominazione utilizzata in questo metodo è simile alla maggior parte dei metodi Objective-C: in inglese semplice. Quindi quando leggi il metodo consentito è ovvio che il metodo "Imposta marca e modello". È importante ricordare che il nome del metodo in questo caso è 'setMake: andModel:' - tutti i titoli degli argomenti sono inclusi nel nome del metodo.

Una nota importante è che usiamo (void) perché i nostri metodi non hanno bisogno di restituire nulla. Dal momento che tutto ciò che stanno facendo è impostare i dati e non è necessario restituire nulla (come un messaggio di successo) semplicemente usiamo void.

Successivamente, aggiungeremo i metodi che useremo per ottenere i valori. Sebbene chiamiamo i nostri metodi per ottenere e impostare metodi, di solito usiamo "set" nel titolo e omettiamo "get". Il modo in cui nominali i metodi dipende da te, ma lasciar cadere "get" è comune e aiuta a evitare confusione.

Il nostro nuovo set di metodi assomiglia a questo:

 // set methods - (void) setVin: (NSNumber *) newVin; - (void) setMake: (NSString *) newMake; - (void) setModel: (NSString *) newModel; // metodo di convenienza - (void) setMake: (NSString *) newMake andModel: (NSString *) newModel; // get metodi - (NSString *) make; - Modello (NSString *); - (NSNumber *) vin; 

Si noti che i metodi get usano gli stessi nomi delle variabili della classe. Questo renderà più semplice il recupero delle variabili. Sarà come se stiamo accedendo direttamente alle variabili, essenzialmente rendendo trasparenti i metodi get.

Codifica l'implementazione

Quindi, ora che l'interfaccia è a posto e sappiamo cosa farà la classe, dobbiamo implementare i nostri metodi. Guardando indietro, abbiamo quattro metodi che dobbiamo implementare: setVin, setMake, setModel e setMake: andModel. Prima di spostare i file, copiare le dichiarazioni del metodo negli Appunti (Cmd + C). Ora chiudi SimpleCar.h e apri SimpleCar.m nell'editor, incollando le dichiarazioni del metodo tra @implementation e @end, in questo modo:

 @implementation SimpleCar // set methods - (void) setVin: (NSNumber *) newVin; - (void) setMake: (NSString *) newMake; - (void) setModel: (NSString *) newModel; // metodo di convenienza - (void) setMake: (NSString *) newMake andModel: (NSString *) newModel; // get metodi - (NSString *) make; - Modello (NSString *); - (NSNumber *) vin; @fine 

Ovviamente non è giusto, quindi quello che dobbiamo fare è scambiare il punto e virgola per le parentesi graffe in cui andranno i meccanismi interni del metodo, in questo modo:

 @implementation SimpleCar // set methods - (void) setVin: (NSNumber *) newVin  - (void) setMake: (NSString *) newMake  - (void) setModel: (NSString *) newModel  - (void) setMake: (NSString *) newMake andModel: (NSString *) newModel  // get metodi - (NSString *) make  - (NSString *) model  - (NSNumber *) vin  @end 

Ora dobbiamo dare qualche codice ai nostri metodi. Iniziamo con i metodi getter perché sono abbastanza semplici. Per ogni metodo getter, tutto ciò che dobbiamo fare è assicurarsi che la funzione restituisca ciò che si intende restituire. Per questo motivo, i nostri metodi getter hanno questo aspetto:

 - (NSString *) make return make;  - (NSString *) model return model;  - (NSNumber *) vin return vin;  

Ricorda: i metodi restituiscono le variabili che abbiamo definito nel file di interfaccia. Non confondersi tra i nomi dei metodi e i nomi delle variabili.

Questo è piuttosto semplice, quando chiamiamo make (ad esempio), quindi make restituisce il puntatore a un NSString - in questo caso alla variabile make. Lo stesso accade per il modello e il vin (eccetto naturalmente vin restituisce un numero).

Ora, per i metodi setter, prima guarderemo il codice e poi lo esamineremo in seguito. I nostri metodi setter assomigliano a questo:

 // set methods - (void) setVin: (NSNumber *) newVin [vin release]; vin = [[NSNumber alloc] init]; vin = newVin;  - (void) setMake: (NSString *) newMake [make release]; make = [[NSString alloc] initWithString: newMake];  - (void) setModel: (NSString *) newModel [release del modello]; model = [[NSString alloc] initWithString: newModel];  // metodo di convenienza - (void) setMake: (NSString *) newMake andModel: (NSString *) newModel // Riutilizza i nostri metodi da precedenti [self setMake: newMake]; [self setModel: newModel];  

I metodi impostati sono un po 'più complicati dei nostri metodi get. Vogliamo allocare i valori che vengono passati in ogni metodo in modo che siano di proprietà della classe. Prima rilasciamo queste variabili nel caso in cui siano già allocate. Se non sono allocati, sono nulli e gli oggetti nulli ignorano i messaggi passati a loro. Tratteremo questi problemi più quando discuteremo della gestione della memoria.

Poiché in realtà abbiamo allocato la memoria per i nostri oggetti nei metodi setter, dobbiamo essere certi che li rilasciamo quando l'oggetto viene rilasciato dalla memoria. Per fare ciò, dobbiamo aggiungere un metodo dealloc personalizzato, in questo modo:

 -(void) dealloc [vin release]; [rendere il rilascio]; [versione del modello]; [super dealloc];  

Test della classe

Congratulazioni! Se hai seguito tutto quanto sopra, ora dovresti avere una classe lavoratrice (se no, scarica i file sorgente disponibili con questo articolo). Quindi, proviamo.

Apri il file principale del tuo progetto (il mio è chiamato CarApp.m) che per impostazione predefinita dovrebbe assomigliare a questo:

 #importare  int main (int argc, const char * argv []) NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; // Inserisci qui il codice personalizzato ... NSLog (@ "Hello, World!"); [scarico piscina]; ritorno 0;  

Eliminare il commento e la riga NSLog in quanto non avremo bisogno di loro in questo momento.

Per iniziare a utilizzare la nostra classe, dobbiamo inserirla nel programma. Sotto la linea #import originale aggiungi la seguente riga:

 #import "SimpleCar.h" 

La nostra classe è ora disponibile per l'uso, ma abbiamo bisogno di crearne un'istanza per testarla. Ecco il codice utilizzato in totale:

 #importare  #import "SimpleCar.h" int main (int argc, const char * argv []) NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; SimpleCar * myCar = [[SimpleCar alloc] init]; NSNumber * newVin = [NSNumber numberWithInt: 123]; [myCar setVin: newVin]; [myCar setMake: @ "Honda" andModel: @ "Civic"]; NSLog (@ "La macchina è:% @% @", [marca myCar], [modello myCar]); NSLog (@ "The vin is:% @", [myCar vin]); [versione myCar]; [scarico piscina]; ritorno 0;  

Prima di tutto creiamo un puntatore a un'istanza di SimpleCar chiamata myCar. Successivamente usiamo alloc e init - questi saranno discussi più avanti su tutta la linea.

Quindi, poiché dobbiamo passare un NSNumber al metodo setVin, ne facciamo uno qui. Di nuovo creiamo un puntatore a un'istanza NSNumber chiamata newVin e iniziamo con il valore intero di 123. La costante '123' è un numero intero, motivo per cui usiamo numberWithInt.

Successivamente, invochiamo i nostri metodi, prima di tutto inseriamo chi dovrebbe ricevere il messaggio (myCar) e quindi usiamo il metodo setVin. Dopo i due punti è il valore che stiamo fornendo al metodo che è il NSNumber che abbiamo creato prima. Poi facciamo lo stesso, ma chiamiamo il metodo setMake con due parametri. Il motivo per cui questi parametri sono preceduti da un segno @ è quello di dire al compilatore che quanto segue è una stringa.

Infine, rilasciamo myCar come abbiamo finito con esso - più su questo più avanti nella serie in gestione della memoria.

La nostra classe ora sta funzionando e, per vedere la dimostrazione, abbiamo aggiunto alcune istruzioni NSLog per stampare i valori sulla console. Se apri la console (Esegui> Console) e poi crei ed esegui la tua app, dovresti vedere un output simile a questo:

Proprietà e sintesi

Se si guarda il codice sopra, molto sembra piuttosto inutile ed eccessivo. Ad esempio, nei nostri metodi getter tutto quello che stiamo facendo è restituire una variabile di istanza - ma questo occupa tre righe di codice per fare qualcosa di semplice. Inoltre, nei nostri metodi setter, stiamo semplicemente impostando le variabili di istanza, in sostanza tutti i nostri metodi, ad eccezione del nostro metodo che prende due argomenti, sembra gonfio e lungo la strada. Objective-C risolve questo problema con @property e @synthesize, che sostituiscono i nostri metodi di accesso e rendono molto più ordinata la codifica.

Ecco come appare il nostro nuovo file di interfaccia con le proprietà:

 #importare  @interface SimpleCar: NSObject NSString * make; Modello NSString *; NSNumber * vin;  @property (readwrite, retain) NSString * make; @property (readwrite, retain) NSString * model; @property (readwrite, retain) NSNumber * vin; // metodo di convenienza - (void) setMake: (NSString *) newMake andModel: (NSString *) newModel; @fine 

Wow, è davvero molto più breve. Quindi cosa sta succedendo con le dichiarazioni @property? Per prima cosa diciamo al compilatore che stiamo dichiarando una proprietà usando @property, quindi seguiamo con gli attributi per questa proprietà. Gli attributi sono lo stato di lettura / scrittura di una proprietà e alcune funzioni di gestione della memoria. Abbiamo usato readwrite per tutti, il che significa che i metodi getter e setter sono creati dinamicamente per le nostre variabili di istanza (potremmo usare writeonly o readonly solo per uno o l'altro). La ragione per cui usiamo mantenere diventerà chiara la prossima volta quando copriremo la gestione della memoria.

Prima che funzioni, è necessario implementarlo nel nostro file di implementazione, lo facciamo usando @synthesize. Il nostro nuovo file di implementazione ha questo aspetto:

 #import "SimpleCar.h" @implementation SimpleCar @synthesize marca, modello, vin; - (void) setMake: (NSString *) newMake andModel: (NSString *) newModel [self setMake: newMake]; [self setModel: newModel];  @fine 

Non sembra migliore? Pensa in questo modo, @property sostituisce tutte le dichiarazioni del metodo di interfaccia per getter e setter e @synthesize sostituisce i metodi effettivi stessi. I getter e i setter sono ora creati dinamicamente e non è necessario perdere tempo a crearli, a meno che non sia necessario fare qualcosa di veramente speciale.

Avvolgendo

Ora dovresti avere una salda presa di classi, oggetti e istanze. Certo, non stai creando classi che cambieranno il mondo, ma questa roba richiede tempo. È meglio imparare dall'esempio, quindi se non stai codificando mentre vai avanti, assicurati di scaricare almeno i file sorgente e di avere una lettura (e una compilazione) per assicurarti di essere al 100% su cosa sta succedendo.

La prossima volta

Abbiamo menzionato molto la gestione della memoria in questo tutorial, è un argomento molto importante che deve essere affrontato (gioco di parole), quindi ci immergeremo in quello la prossima volta. È vero, non è il soggetto più divertente o il più facile da accettare, ma è assolutamente cruciale se vuoi diventare un abile programmatore Objective-C.

Sfida

La sfida di questa settimana potrebbe essere un po 'complicata, ma vedremo come procederai. Prima di tutto, se non hai copiato tutto il codice sopra, scarica i file sorgente inclusi in questo articolo. La sfida è aggiungere un'altra classe al progetto, ma questa volta dovrebbe essere una sottoclasse di SimpleCar (ricordate, definiamo la classe genitore nel file di interfaccia). Se puoi farlo, gioca e usa i metodi ereditati e prova ad aggiungere il tuo per cose come: dimensioni del motore, porte o altezza.

Ricorda: se hai domande o domande, lascia un commento qui sotto o inviami un messaggio su Twitter. L'unica domanda stupida è quella che non hai chiesto - questa serie riguarda l'apprendimento quindi sentiti libero di chiedere!