Lær objektiv-C Dag 4

Velkommen til del fire av denne serien på Objective-C. Så langt har vi sett mye på teori og prinsippene og funksjonaliteten til språket for å få en god ide om hvordan det fungerer. I dag skal vi lage en enkel klasse som ligner på bileksemplet vi så på i tidligere deler av denne serien. Vår klasse tar informasjon om en bil, slik at vi kan få og angi verdiene som holdes. Etter dagens eksempel bør du kunne lage dine egne klasser i Xcode og leke rundt med dem.

Så langt har vi hatt noen gode tilbakemeldinger via e-post, twitter og kommentarer. Det er flott å se så mange mennesker er interessert i dette emnet, og det er enda bedre å se at så mange av dere prøver det selv og spør noen flotte spørsmål. Hold det oppe!

Starter

Start med å skyte opp Xcode og opprette et nytt prosjekt. Under Mac OS X-separatoren klikker du Program, og deretter Kommandolinjeverktøy. Endelig, endrer rullegardinmenyen for å angi typen til Stiftelsen.

Lagre prosjektet som hva du vil, jeg ringte min CarApp. Når prosjektvinduet vises, må vi opprette en ny klasse. Hit Command-N (eller File> New File), naviger til kakao klasse under Mac OS X og velg Objective-C klasse. Pass på at Subclass of er satt til NSObject og trykk Next. Navngi klassen SimpleCar og sørg for at en .h-fil opprettes, og lagre den.

Vår klasse eksisterer nå, men det gjør ingenting. La oss endre det ved å gi det noen kode. Husk at i Objective-C deler vi koden vår i to deler: grensesnitt og implementering. Det er logisk fornuftig å jobbe med grensesnittet først, så det er her vi skal begynne.

Koding av grensesnittet

Åpne filen SimpleCar.h, og i den nåværende tilstanden skal den se slik ut (jeg har utelatt kommentarhodet nedenunder)

 #importere  @interface SimpleCar: NSObject  @end 

Først av alt, inkluderer vi Cocoa.h, som gir oss tilgang til slike ting som NSString, NSMutableString, etc. Deretter lager vi vår klasse (SimpleCar) som en underklasse av NSObject.

Nå må vi bestemme hvilken informasjon vår klasse må lagre. Siden vi bruker en bil som vårt eksempel, må vi lagre bilrelatert informasjon, for eksempel:

  • Gjøre
  • Modell
  • VIN

Det er mye mer vi kunne gå inn i, men for nå som vil gjøre det. For hver av disse egenskapene må vi lagre dem i en variabel som passer for den typen data. Lag og modell vil være en rekke tegn (for eksempel tekst, tall og muligens tegnsetting), så det er fornuftig å bruke en streng. VIN-nummeret (Vehicle Identification Number) vil bare være et nummer, så det er det vi skal bruke. Vår kode ser nå ut som dette (overskrift utelatt):

 @interface SimpleCar: NSObject NSString * lage; NSString * modell; NSNummer * vin;  @slutt 

Vi har tidligere sagt at for å få eller sette data fra en klasse, bør en metode brukes. Så for å angi variablene må vi legge til metoder. For å gjøre dette skal vi lage fire: en vil sette merke, en modell, en VIN, og en endelig metode vil sette både make AND modell (bare for å vise deg hvordan du bruker flere argumenter).

 @interface SimpleCar: NSObject NSString * lage; NSString * modell; NSNummer * vin;  // sett metoder - (void) setVin: (NSNumber *) newVin; - (void) setMake: (NSString *) newMake; - (void) setModel: (NSString *) setModel; // bekvemmelighetsmetode - (void) setMake: (NSString *) newMake andModel: (NSString *) newModel; @slutt 

Vi erklærer metoder etter den krøllete braketten og før @end. Ved å plassere et dash (minustegn) før metoden, forteller vi kompilatoren vi skal erklære en instansmetode. En instansmetode er en metode som er utført på vår forekomst. Omvendt indikerer et plussignal at metoden som påberopes, er en klassemetode som ikke trenger en individuell objekteksempel å utføre - videre på dette senere.

Vår første metode returnerer tomrom, kalles setVin og tar en NSNummer som et argument. Vår andre metode er lik, den returnerer tom, er call setMake, og tar en NSString som et argument. Den tredje er den samme, med et annet navn.

Vår siste metode returnerer også tomt, men tar to parametere: newMake og newModel, som begge skal være NSString. Navngivningen som brukes i denne metoden, ligner på hvordan de fleste mål-C-metodene heter: på vanlig engelsk. Så når du leser metoden som er tillatt, er det åpenbart at metoden vil "Sett merke og modell." Det er viktig å huske at metodenavnet i dette tilfellet er 'setMake: andModel:' - alle argumenttitlene er inkludert i metodenavnet.

Et viktig notat er at vi bruker (ugyldig) fordi våre metoder ikke trenger å returnere noe. Siden alt de gjør er å sette inn data og ikke trenger å returnere noe tilbake (for eksempel en suksessmelding) bruker vi bare tomrom.

Deretter legger vi til de metodene vi skal bruke for å få verdiene. Selv om vi kaller våre metoder, får og sett metoder, bruker vi vanligvis bare "sett" i tittelen og utelater "få". Hvordan du navngi metodene dine, er i det hele tatt opp til deg, men å slippe "få" er vanlig og hjelper til med å unngå forvirring.

Vårt nye sett med metoder ser slik ut:

 // sett metoder - (void) setVin: (NSNumber *) newVin; - (void) setMake: (NSString *) newMake; - (void) setModel: (NSString *) newModel; // bekvemmelighetsmetode - (void) setMake: (NSString *) newMake andModel: (NSString *) newModel; // få metoder - (NSString *) gjør; - (NSString *) modell; - (NSNummer *) vin; 

Legg merke til at få-metodene bruker de samme navnene som variablene i klassen. Dette gjør det enkelt når vi henter variablene. Det vil være som om vi får tilgang til variablene direkte, noe som i hovedsak gjør at få-metodene vises gjennomsiktige.

Koding av implementeringen

Så nå som grensesnittet er på plass og vi vet hva klassen vil gjøre, må vi implementere våre metoder. Når vi ser tilbake, har vi fire metoder vi må implementere: setVin, setMake, setModel og setMake: andModel. Før vi flytter filer, kopier du metoden deklarasjoner til utklippstavlen din (Cmd + C). Nå lukk SimpleCar.h og brann opp SimpleCar.m i redigeringsprogrammet, og lim inn metodedeklarasjonene mellom @implementation og @end, slik som:

 @implementation SimpleCar // sett metoder - (void) setVin: (NSNumber *) newVin; - (void) setMake: (NSString *) newMake; - (void) setModel: (NSString *) newModel; // bekvemmelighetsmetode - (void) setMake: (NSString *) newMake andModel: (NSString *) newModel; // få metoder - (NSString *) gjør; - (NSString *) modell; - (NSNummer *) vin; @slutt 

Tydeligvis er dette ikke riktig, så det vi trenger å gjøre er å bytte halvkolonene for krøllede parenteser der metodens indre virkninger vil gå slik:

 @implementation SimpleCar // sett metoder - (void) setVin: (NSNumber *) newVin  - (void) setMake: (NSString *) newMake  - (void) setModel: (NSString *) newModel  - (void) setMake: (NSString *) newMake andModel: (NSString *) newModel  // få metoder - (NSString *) gjør  - (NSString *) modell  - (NSNummer *) vin  @end 

Nå må vi gi våre metoder noen kode. La oss starte med getter-metodene som de er rettferdige nok. For hver getter-metode er alt vi trenger å gjøre, å sørge for at funksjonen returnerer hva den er ment å returnere. Av denne grunn ser våre getter-metoder ut slik:

 - (NSString *) gjør return make;  - (NSString *) modell returmodell;  - (NSNummer *) vin return vin;  

Huske: metodene returnerer variablene vi definerte i grensesnittfilen. Ikke bli forvirret mellom metodenavnene og de variable navnene.

Det er ganske greit, når vi kaller make (for eksempel), så returnerer pekeren til en NSString - i dette tilfellet til make-variabelen. Det samme skjer for modell og vin (bortsett fra at vin returnerer et tall).

Nå for setter metoder, først ser vi på koden og så går vi gjennom det etterpå. Våre settermetoder ser slik ut:

 // sett metoder - (void) setVin: (NSNumber *) newVin [vin release]; vin = [[NSNummer allokering] init]; vin = newVin;  - (void) setMake: (NSString *) newMake [frigjøre]; lage = [[NSString alloker] initWithString: newMake];  - (void) setModel: (NSString *) newModel [modellutgivelse]; modell = [[NSString alloker] initWithString: newModel];  // bekvemmelighetsmetode - (void) setMake: (NSString *) newMake andModel: (NSString *) newModel // Gjenbruk våre metoder fra tidligere [self setMake: newMake]; [self setModel: newModel];  

De angitte metodene er litt vanskeligere enn våre metoder. Vi ønsker å tildele verdiene som sendes inn i hver metode slik at de eies av klassen. Vi slipper først disse variablene i tilfelle de allerede er tildelt. Hvis de ikke er allokert, er de null, og null objekter ignorerer meldinger som sendes til dem. Vi vil dekke disse problemene mer når vi diskuterer minnehåndtering.

Fordi vi faktisk har tildelt minne for våre objekter i settermetodene, må vi være sikker på at vi slipper dem når objektet er utgitt fra minnet. For å gjøre dette må vi legge til en tilpasset deallokmetode, slik som:

 -(void) dealloc [vinutgivelse]; [gjør utgivelse]; [modellutgivelse]; [super dealloc];  

Testing av klassen

Gratulerer! Hvis du fulgte alt over, bør du nå ha en arbeiderklasse (hvis ikke, last ned kildefilene som er tilgjengelige med denne artikkelen). Så, la oss teste det ut.

Åpne hovedfilen til prosjektet ditt (min heter CarApp.m) som som standard skal se slik ut:

 #importere  int main (int argc, const char * argv []) NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; // Sett inn egendefinert kode her ... NSLog (@ "Hei, Verden!"); [bassengdrenering]; returner 0;  

Slett kommentaren og NSLog-linjen da vi ikke trenger dem akkurat nå.

For å kunne begynne å bruke vår klasse, må vi trekke den inn i programmet. Under den opprinnelige #import-linjen legger du til følgende linje:

 #import "SimpleCar.h" 

Vår klasse er nå tilgjengelig for bruk, men vi må lage en forekomst av den for å teste den ut. Her er koden som brukes totalt:

 #importere  #import "SimpleCar.h" int main (int argc, const char * argv []) NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; SimpleCar * myCar = [[SimpleCar alloc] init]; NSNummer * newVin = [NSNummer nummerWithInt: 123]; [myCar setVin: newVin]; [myCar setMake: @ "Honda" ogModel: @ "Civic"]; NSLog (@ "Bilen er:% @% @", [myCar make], [myCar-modellen]); NSLog (@ "Vinen er:% @", [myCar vin]); [myCar release]; [bassengdrenering]; returner 0;  

Først av alt lager vi en peker til en forekomst av SimpleCar som heter myCar. Neste bruker vi allokering og init - disse vil bli diskutert senere nedover linjen.

Siden vi må sende en NSNummer til setVin-metoden, lager vi en her. Igjen skaper vi en peker til en NSNummer-instans kalt newVin, og vi starter det med heltallverdien på 123. Konstanten '123' er et heltall, derfor bruker vi nummer medIt.

Deretter bruker vi våre metoder, først og fremst setter vi hvem som skal motta meldingen (myCar) og så bruker vi metoden setVin. Etter kolon er verdien vi leverer til metoden som er NSNummeret vi opprettet før. Neste gjør vi det samme, men kaller setMake-metoden med to parametere. Grunnen til at disse parameterne er foran et @ -tegn er å fortelle kompilatoren at følgende er en streng.

Endelig slipper vi myCar etter hvert som vi er ferdige med det - mer om dette senere i serien under minnestyring.

Vår klasse jobber nå, og for å se beviset har vi lagt til noen NSLog-setninger for å skrive ut verdiene til konsollen. Hvis du åpner konsollen (Kjør> Konsoll), og deretter bygger og kjører appen din, bør du se utdata som ligner dette:

Eiendom og Synthesize

Hvis du ser på koden ovenfor, virker det som om det er ganske meningsløst og overdrevet. For eksempel, i våre getter-metoder er alt vi gjør, å returnere en instansvariabel - men dette tar opp tre linjer med kode for å gjøre noe enkelt. Også i våre setter metoder, er vi bare å sette instansvariabler - i hovedsak alle våre metoder, bortsett fra vår metode som tar to argumenter, virker oppblåst og i veien. Mål-C løser dette med @property og @synthesize, som erstatter våre tilgangsmetoder og gir mye mer nøyaktig koding.

Dette er hva vår nye grensesnittfil ser ut som å bruke egenskaper:

 #importere  @interface SimpleCar: NSObject NSString * lage; NSString * modell; NSNummer * vin;  @property (readwrite, behold) NSString * lage; @property (readwrite, behold) NSString * modell; @property (readwrite, behold) NSNumber * vin; // bekvemmelighetsmetode - (void) setMake: (NSString *) newMake andModel: (NSString *) newModel; @slutt 

Wow, det er virkelig mye kortere. Så hva skjer med @property deklarasjonene? Først forteller vi kompilatoren vi erklærer en eiendom ved å bruke @property, så følger vi med attributter for denne eiendommen. Attributtene er lese / skrive status for en eiendom og litt minnehåndtering. Vi har brukt readwrite for alle, noe som betyr at getter og setter-metoder blir dynamisk opprettet for våre instansvariabler (vi kunne brukes til skrivewrit eller readonly for bare den ene eller den andre). Grunnen til at vi bruker beholdningen blir klar neste gang vi dekker minnehåndtering.

Før dette kan fungere, må vi implementere det i implementasjonsfilen vår, dette gjør vi ved å bruke @synthesize. Vår nye implementeringsfil ser slik ut:

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

Ser det ikke bedre ut? Tenk på det som dette, @property erstatter alle grensesnittmetodedeklarasjoner for getters og setters, og @synthesize erstatter selve metodene selv. Getters og setters er nå dynamisk opprettet, og vi trenger ikke å kaste bort tid på å skape dem med mindre vi trenger å gjøre noe veldig spesielt.

Wrapping Up

Du bør nå ha et fast grep om klasser, objekter og forekomster. Jo, du skaper ikke klasser som vil forandre verden ennå, men dette tar tid. Det er bedre å lære ved eksempel, så hvis du ikke er koding som du går sammen, så husk å laste ned kildefilene og lese gjennom (og kompilere) for å sikre at du er 100% på hva som skjer.

Neste gang

Vi har nevnt minnehåndtering mye i denne opplæringen, det er et veldig viktig emne som må adresseres (ordspill beregnet), så vi vil dykke inn til neste gang. Det er sant, det er ikke det mest morsomme emnet eller det enkleste å komme til med, men det er helt avgjørende hvis du vil bli en dyktig Objective-C programmerer.

Utfordring

Ukens utfordring kan være litt vanskelig, men vi får se hvordan du går videre. Først og fremst, hvis du ikke har kopiert all koden ovenfor, last ned kildefilene som følger med denne artikkelen. Utfordringen er å legge til en annen klasse i prosjektet, men denne gangen bør det være en underklasse av SimpleCar (husk, vi definerer foreldreklassen i grensesnittfilen). Hvis du kan gjøre det, lek deg og bruk de arvede metodene og prøv å legge til dine egne for ting som: motorstørrelse, dører eller høyde.

Huske: Hvis du har noen spørsmål eller spørsmål, slipp en kommentar nedenfor eller skyt meg en melding på Twitter. Det eneste dumme spørsmålet er det du ikke spurte - denne serien handler om å lære, så vær så snill å spørre deg bort!