Bine ați venit la partea a patra a acestei serii despre Obiectiv-C. Până acum, am analizat foarte mult teoria și principiile și funcționalitatea limbajului pentru a obține o idee bună despre cum funcționează. Astăzi, vom face o clasă simplă similară exemplului de mașină pe care l-am privit în părțile anterioare ale acestei serii. Clasa noastră va lua detaliile unei mașini, permițându-ne să obținem și să stabilim valorile deținute. După exemplul de astăzi, ar trebui să puteți crea propriile clase în Xcode și să jucați în jurul lor cu ele.
Până în prezent, am avut niște feedback minunat prin e-mail, twitter și comentarii. Este minunat să vedem că atât de mulți oameni sunt interesați de acest subiect și este chiar mai bine să vedem că atât de mulți dintre voi îl încercați pentru dvs. și puneți câteva mari întrebări. Ține-o așa!
Începeți prin arderea Xcode și crearea unui nou proiect. Sub separatorul Mac OS X, faceți clic pe Aplicație, apoi pe Instrument linie de comandă. În cele din urmă, schimbați caseta verticală pentru a seta tipul la Fundație.
Salvați proiectul ca pe orice vreți, l-am sunat pe CarApp. După ce apare fereastra proiectului, trebuie să creați o nouă clasă. Apăsați Command-N (sau File> File New), navigați la Cocoa Class sub Mac OS X și selectați Class Objective-C. Asigurați-vă că subclasa este setată la NSObject și apăsați Next. Denumiți clasa SimpleCar și asigurați-vă că va fi creat un fișier .h, apoi salvați-l.
Clasa noastră există acum, dar nu face nimic. Să schimbăm asta dându-i un cod. Amintiți-vă că în Obiectiv-C am împărțit codul nostru în două părți: interfață și implementare. Este logic să lucrăm mai întâi la interfață, de aceea vom începe.
Deschideți fișierul SimpleCar.h și în starea sa actuală ar trebui să arate astfel (am omis antetul de comentariu de mai jos)
#import@interface SimpleCar: NSObject @end
Mai întâi de toate, includem și Cocoa.h, care ne oferă acces la astfel de lucruri ca NSString, NSMutableString, etc. Apoi, creăm clasa noastră (SimpleCar) ca subclasă de NSObject.
Acum trebuie să decidem ce informații trebuie să stocheze clasa noastră. Deoarece folosim o mașină ca exemplu, trebuie să stocăm informații legate de mașină, cum ar fi:
Mai sunt multe lucruri pe care le-am putea intra, dar deocamdată asta o va face. Pentru fiecare dintre aceste proprietăți, trebuie să le stocăm într-o variabilă potrivită pentru acel tip de date. Marca și modelul vor fi o serie de caractere (cum ar fi text, număr și eventual punctuație), astfel că este logic să folosiți un șir. Numărul VIN (numărul de identificare a vehiculului) va fi doar un număr, așa că vom folosi. Codul nostru arată acum (antetul este omis):
@interface SimpleCar: NSObject NSString * make; Modelul NSString *; NSNumber * vin; @Sfârșit
Am spus anterior că, pentru a obține sau a seta date dintr-o clasă, ar trebui utilizată o metodă. Deci, pentru a seta variabilele, trebuie să adăugăm metode. Pentru a face acest lucru, vom face patru: una va stabili marca, un model, un VIN, iar o metoda finala va stabili atat modelul AND, cat si modelul (pentru a va arata cum sa folositi mai multe argumente).
@interface SimpleCar: NSObject NSString * make; Modelul NSString *; NSNumber * vin; // set metode - (void) setVin: (NSNumber *) newVin; - (void) setMake: (NSString *) newMake; - (void) setModel: (NSString *) setModel; // Metoda comoditate - (void) setMake: (NSString *) newMake andModel: (NSString *) newModel; @Sfârșit
Declarăm metode după brațul curbat și înainte de @end. Prin plasarea unei liniuțe (semn minus) înaintea metodei, îi spunem compilatorului că vom declara o metodă instanță. O metodă instanță este o metodă executată pe instanța noastră. În schimb, un semn plus indică faptul că metoda invocată este o metodă de clasă care nu are nevoie de o instanță a unui obiect individual pentru a executa - mai mult despre aceasta mai târziu.
Prima noastră metodă returnează void, se numește setVin și ia un NSNumber ca argument. A doua noastră metodă este similară, se întoarce nevalidă, este call setMake, și ia un argument NSString ca argument. Al treilea este același, cu un nume diferit.
Metoda noastră finală se întoarce, de asemenea, nevalidă, însă are doi parametri: newMake și newModel, ambii care ar trebui să fie NSString. Denumirea folosită în această metodă este similară cu cea pe care o numesc cele mai multe metode Obiectiv-C: în engleză simplă. Deci, atunci când citiți metoda permisă, este evident că metoda va "seta marca și modelul". Este important să rețineți că numele metodei în acest caz este 'setMake: șiModel:' - toate titlurile de argument sunt incluse în numele metodei.
O notă importantă este că folosim (void), deoarece metodele noastre nu trebuie să returneze nimic. Deoarece tot ceea ce fac sunt setarea de date și nu este nevoie să returneze nimic înapoi (cum ar fi un mesaj de succes), pur și simplu folosim void.
Apoi, vom adăuga metodele pe care le vom folosi pentru a obține valorile. Deși numim metodele noastre de a obține și de a stabili metode, de obicei folosim doar "set" în titlu și omiteți "obțineți". Modul în care vă numiți metodele este în cele din urmă la latitudinea dvs., dar renunțarea la "obținere" este obișnuită și ajută la evitarea confuziei.
Noul nostru set de metode arată astfel:
// setarea metodelor - (void) setVin: (NSNumber *) newVin; - (void) setMake: (NSString *) newMake; - (void) setModel: (NSString *) newModel; // Metoda comoditate - (void) setMake: (NSString *) newMake andModel: (NSString *) newModel; // a lua metode - (NSString *) face; - modelul (NSString *); - (NSNumber *) vin;
Observați că metodele de obținere folosesc aceleași nume ca și variabilele din clasă. Acest lucru va face mai simplu atunci când vom prelua variabilele. Va fi ca și cum vom accesa variabilele în mod direct, făcând în esență metode de a deveni transparente.
Deci acum că interfața este în vigoare și știm ce va face clasa, trebuie să implementăm metodele noastre. Privind înapoi, avem patru metode pe care trebuie să le implementăm: setVin, setMake, setModel și setMake: șiModel. Înainte de a muta fișierele, copiați declarațiile de metodă în clipboard (Cmd + C). Acum, închideți SimpleCar.h și aprindeți SimpleCar.m în editor, adăugând declarațiile metodelor între @implementation și @end, cum ar fi:
@implementation SimpleCar // set metode - (void) setVin: (NSNumber *) newVin; - (void) setMake: (NSString *) newMake; - (void) setModel: (NSString *) newModel; // Metoda comoditate - (void) setMake: (NSString *) newMake andModel: (NSString *) newModel; // a lua metode - (NSString *) face; - modelul (NSString *); - (NSNumber *) vin; @Sfârșit
Evident, acest lucru nu este corect, deci ceea ce trebuie să facem este să schimbăm semi-colonii pentru paranteze curbate, unde funcționarea interioară a metodei va merge, după cum urmează:
@implementare SimpleCar // metode setate - (void) setVin: (NSNumber *) newVin - (void) setMake: (NSString *) newMake - (void) setModel: setMake: (NSString *) newMake șiModel: (NSString *) newModel // obține metode - (NSString *) face - (NSString *) model - (NSNumber *) vin @end
Acum trebuie să dăm metodelor noastre un cod. Să începem cu metodele getter deoarece sunt destul de simple. Pentru fiecare metodă getter, tot ce trebuie să faceți este să vă asigurați că funcția returnează ceea ce se intenționează să se întoarcă. Din acest motiv, metodele noastre getter arată astfel:
- (NSString *) face return make; - (NSString *) model return model; - (NSNumber *) vin retur vin;
Tine minte: metodele returnează variabilele definite în fișierul de interfață. Nu vă confundați între numele metodelor și numele variabilelor.
Este destul de simplă, atunci când numim make (de exemplu), apoi face să se întoarcă pointerul la un NSString - în acest caz la variabila make. Același lucru se întâmplă pentru model și vin (cu excepția, desigur, vin întoarce un număr).
Acum, pentru metodele de setare, mai întâi vom examina codul și apoi vom trece prin el după aceea. Metodele noastre de setare arată astfel:
// set metode - (void) setVin: (NSNumber *) newVin [lansare vin]; vin = [[NSNumber alin] init]; vin = newVin; - (void) setMake: (NSString *) newMake [lansare]; make = [[NSString alin] initWithString: newMake]; - (void) setModel: (NSString *) newModel [release model]; model = [[NSString alloc] initWithString: newModel]; // metoda comodă - (void) setMake: (NSString *) newMake andModel: (NSString *) newModel // Reutilizarea metodelor noastre de la [self setMake: newMake]; [auto setModel: newModel];
Metodele stabilite sunt puțin mai complicate decât metodele noastre de a obține. Vrem să alocăm valorile care sunt transmise în fiecare metodă astfel încât acestea să fie deținute de clasă. Mai întâi lansăm aceste variabile în cazul în care sunt deja alocate. Dacă nu sunt alocate, atunci ele sunt zero, iar obiectele nula ignoră mesajele transmise acestora. Vom aborda mai mult aceste probleme atunci când discutăm despre gestionarea memoriei.
Pentru că de fapt am alocat memorie obiectelor noastre în metodele setter, trebuie să fim siguri că le eliberăm atunci când obiectul este eliberat din memorie. Pentru a face acest lucru, trebuie să adăugăm o metodă personalizată dealloc, după cum urmează:
-(void) dealloc [release vin]; [a elibera]; [model release]; [super dealloc];
Felicitări! Dacă ați urmat totul de mai sus atunci ar trebui să aveți acum o clasă muncitoare (dacă nu, descărcați fișierele sursă disponibile cu acest articol). Deci, hai să încercăm.
Deschideți fișierul principal al proiectului dvs. (al meu se numește CarApp.m) care ar trebui să arate în mod implicit în felul următor:
#importint principal (int argc, const char * argv []) NSAutoreleasePool * pool = [[NSAutoreleasePool aliniere] init]; // Introduceți codul personalizat aici ... NSLog (@ "Hello, World!"); [scurgere piscină]; retur 0;
Ștergeți comentariul și linia NSLog, deoarece nu vom avea nevoie de ele chiar acum.
Pentru a începe să folosim clasa noastră, trebuie să o luăm în program. Sub linia #import originală, adăugați următoarea linie:
#import "SimpleCar.h"
Clasa noastră este acum disponibilă pentru utilizare, dar trebuie să creați o instanță a acesteia pentru a le testa. Iată codul utilizat în total:
#import#import "SimpleCar.h" int principal (int argc, const char * argv []) NSAutoreleasePool * pool = [[NSAutoreleasePool alocare] init]; SimpleCar * myCar = [[SimpleCar aloca] init]; NSNumber * newVin = [NSNumber numberWithInt: 123]; [myCar setVin: newVin]; [myCar setMake: @ "Honda" șiModel: @ "Civic"]; NSLog (@ "Mașina este:% @% @", [myCar make], [modelul myCar]); NSLog (@ "Vinul este:% @", [myCar vin]); [release myCar]; [scurgere piscină]; retur 0;
Mai intai vom crea un pointer la un exemplu de SimpleCar numit myCar. Apoi vom folosi alocarea și init - acestea vor fi discutate mai târziu pe linie.
În continuare, deoarece trebuie să trecem un NSNumber la metoda setVin, facem una aici. Din nou, creăm un pointer la o instanță NSNumber numită newVin și o inițiazăm cu valoarea întregului de 123. Constanta '123' este un număr întreg, de aceea folosim numărulWithInt.
Apoi, ne invocăm metodele noastre, mai întâi de toate am pus cine ar trebui să primească mesajul (myCar) și apoi vom folosi metoda setVin. După colon este valoarea pe care o furnizăm metodei care este NSNumber pe care am creat-o înainte. Apoi vom face același lucru, dar vom apela metoda setMake cu doi parametri. Motivul pentru care acești parametri sunt precedați de un semn @ este să spună compilatorului că următorul text este un șir.
În cele din urmă, lansăm myCar așa cum am terminat - mai multe despre aceasta mai târziu în seria de gestionare a memoriei.
Clasa noastră funcționează acum și, pentru a vedea dovada, am adăugat câteva declarații NSLog pentru a imprima valorile la consola. Dacă deschideți consola (Run> Console) și apoi construiți și executați aplicația, ar trebui să vedeți ieșire similară cu aceasta:
Dacă te uiți la codul de mai sus, multe dintre ele par destul de inutile și excesive. De exemplu, în metodele noastre getter tot ceea ce facem este returnarea unei variabile de instanță - dar acest lucru necesită trei linii de cod pentru a face ceva simplu. De asemenea, în metodele noastre de setare, setăm doar variabile de instanță - în esență, toate metodele noastre, cu excepția metodei noastre care are două argumente, pare umflată și în cale. Obiectiv-C rezolvă acest lucru cu @property și @synthesize, care înlocuiesc metodele noastre accessor și face pentru codificare mult mai neater.
Acesta este ceea ce arată noul nostru fișier de interfață utilizând proprietățile:
#import@interface SimpleCar: NSObject NSString * make; Modelul NSString *; NSNumber * vin; @property (citiți, rețineți) NSString * face; @property (citiți, rețineți) modelul NSString *; @property (citiți, păstrați) NSNumber * vin; // Metoda comoditate - (void) setMake: (NSString *) newMake andModel: (NSString *) newModel; @Sfârșit
Wow, că într-adevăr este mult mai scurt. Deci, ce se întâmplă cu declarațiile @property? Mai întâi spunem compilatorului că declarăm o proprietate folosind @property, apoi urmăm cu atributele pentru această proprietate. Atributele sunt starea de citire / scriere a unei proprietăți și o anumită gestionare a memoriei. Am folosit citirea pentru toate, ceea ce înseamnă că metodele getter și setter sunt create dinamic pentru variabilele noastre de instanță (am putea să le folosim în scris sau în citire doar pentru unul sau altul). Motivul pentru care folosim reținerea va deveni clar data viitoare când vom acoperi gestionarea memoriei.
Înainte de a putea funcționa, trebuie să îl implementăm în fișierul nostru de implementare, facem acest lucru folosind @synthesize. Noul nostru fișier de implementare arată astfel:
#import "SimpleCar.h" @implementation SimpleCar @synthesize face, model, vin; - (void) setMake: (NSString *) newMake șiModel: (NSString *) newModel [self setMake: newMake]; [auto setModel: newModel]; @Sfârșit
Nu arata mai bine? Gândiți-vă astfel, @property înlocuiește toate declarațiile metodei interfeței pentru getters și setters, iar @synthesize înlocuiește metodele reale. Obținătorii și setterii sunt acum creați dinamic și nu avem nevoie să pierdem timpul creându-le dacă nu trebuie să facem ceva cu adevărat special.
Acum ar trebui să aveți o aderență fermă la clase, obiecte și instanțe. Sigur, nu creați clase care să schimbe încă lumea, dar chestia asta are nevoie de timp. Este mai bine să înveți prin exemplu, deci dacă nu codificați pe măsură ce mergeți, asigurați-vă că cel puțin descărcați fișierele sursă și citiți (și compilați) pentru a vă asigura că sunteți 100% pe ce se întâmplă.
Am menționat foarte mult managementul memoriei în acest tutorial, este un subiect foarte important care trebuie abordat (cu intenția de a veni în joc), așa că ne vom arunca cu capul la următoarea dată. Adevărat, nu este cel mai distractiv subiect sau cel mai ușor de înțeles, dar este absolut esențial dacă vrei să devii un programator Obiectiv-C calificat.
Provocările din această săptămână pot fi puțin complicate, dar vom vedea cum te descurci. Mai întâi, dacă nu ați copiat tot codul de mai sus, descărcați fișierele sursă incluse în acest articol. Provocarea este să adăugați o altă clasă la proiect, dar de această dată ar trebui să fie o subclasă a SimpleCar (amintiți-vă, definim clasa parentală în fișierul de interfață). Dacă puteți face acest lucru, jucați în jur și utilizați metodele moștenite și încercați să adăugați propriile dvs. pentru lucruri precum: dimensiunea motorului, ușile sau înălțimea.
Tine minte: dacă aveți întrebări sau interogări, renunțați la un comentariu de mai jos sau împușcați-mi un mesaj pe Twitter. Singura întrebare stupidă este cea pe care nu o întrebați - această serie este despre învățare, deci nu ezitați să întrebați!