Välkommen till del fyra i den här serien om Objective-C. Hittills har vi tittat mycket på teori och språkets principer och funktionalitet för att få en bra bild av hur det fungerar. Idag ska vi göra en enkel klass som liknar det bilexempel som vi tittade på i tidigare delar av serien. Vår klass tar detaljer om en bil, så att vi kan få och ställa in de värden som hålls. Efter dagens exempel borde du kunna skapa egna klasser i Xcode och leka runt med dem.
Hittills har vi fått bra feedback via e-post, twitter och kommentarer. Det är kul att se så många människor är intresserade av detta ämne och det är ännu bättre att se så många av dig själv försöker ut det och frågar några bra frågor. Fortsätt så!
Börja med att skjuta upp Xcode och skapa ett nytt projekt. Under Mac OS X-separatorn klickar du på Program och klickar sedan på Kommandoradverktyg. Ändra slutligen nedrullningsrutan för att ställa in typen till Foundation.
Spara projektet som vad du vill, jag ringde min CarApp. När projektfönstret visas måste vi skapa en ny klass. Hit Command-N (eller File> New File), navigera till Cocoa Class under Mac OS X och välj Objective-C class. Se till att Subclass of är inställd på NSObject och tryck på Next. Namnge din klass SimpleCar och se till att en .h-fil skapas, spara sedan den.
Vår klass finns nu, men det gör ingenting. Låt oss ändra det genom att ge det lite kod. Kom ihåg att i Objective-C delar vi vår kod i två delar: gränssnitt och implementering. Det gör logisk mening att arbeta på gränssnittet först, så det är där vi ska börja.
Öppna filen SimpleCar.h och i sitt nuvarande tillstånd ska det se ut så här (jag har utelämnat kommentarhuvudet nedanifrån)
#importera@interface SimpleCar: NSObject @end
Först och främst inkluderar vi Cocoa.h, vilket ger oss tillgång till saker som NSString, NSMutableString etc. Därefter skapar vi vår klass (SimpleCar) som en undergrupp av NSObject.
Nu måste vi bestämma vilken information vår klass behöver för att lagra. Eftersom vi använder en bil som vårt exempel måste vi lagra bilrelaterad information, till exempel:
Det finns mycket mer vi kunde gå in i, men för nu som ska göra. För var och en av dessa egenskaper måste vi lagra dem i en variabel som är anpassad för den typen av data. Make och modell kommer att vara en rad tecken (t.ex. text, nummer och eventuellt skiljetecken) så det är vettigt att använda en sträng. VIN (Vehicle Identification Number) kommer bara att vara ett nummer så det är vad vi ska använda. Vår kod ser nu ut så här (rubrik utelämnad):
@interface SimpleCar: NSObject NSString * make; NSString * modell; NSNumber * vin; @slutet
Vi har tidigare sagt att för att få eller ställa in data från en klass bör en metod användas. Så för att ställa in variablerna måste vi lägga till metoder. För att göra detta kommer vi att göra fyra: en kommer att göra tillverkningen, en modell, en VIN, och en slutlig metod kommer att ställa in både make AND modell (bara för att visa dig hur du använder flera argument).
@interface SimpleCar: NSObject NSString * make; NSString * modell; NSNumber * vin; // Ange metoder - (void) setVin: (NSNumber *) newVin; - (tomrum) setMake: (NSString *) newMake; - (tomrum) setModel: (NSString *) setModel; // bekvämlighet metod - (void) setMake: (NSString *) newMake andModel: (NSString *) newModel; @slutet
Vi förklarar metoder efter den krökta fästet och före @end. Genom att placera ett streck (minustecken) före metoden berättar vi kompilatorn vi ska förklara en förekomstmetod. En instansmetod är en metod som utförs på vår förekomst. Omvänt indikerar ett plustecken att metoden som åberopas är en klassmetod som inte behöver en enskild objektinstans att genomföra-längre senare.
Vår första metod returnerar void, heter setVin och tar en NSNumber som ett argument. Vår andra metod är likadan, den returnerar ogiltig, är call setMake och tar en NSString som ett argument. Den tredje är densamma, med ett annat namn.
Vår sista metod returnerar också tomt men tar två parametrar: newMake och newModel, vilka båda borde vara NSString. Namnet som används i denna metod liknar hur de flesta objektiv-C-metoderna heter: på vanlig engelska. Så när du läser metoden tillåten är det uppenbart att metoden kommer att "Ställ make och modell." Det är viktigt att komma ihåg att metodnamnet i detta fall är 'setMake: andModel:' - alla argumenttitlar ingår i metodnamnet.
En viktig anteckning är att vi använder (tomrum) eftersom våra metoder inte behöver returnera någonting. Eftersom allt de gör är inställning av data och behöver inte returnera något tillbaka (som ett framgångsbudskap) använder vi helt enkelt tomrum.
Därefter kommer vi att lägga till de metoder vi ska använda för att få värdena. Även om vi kallar våra metoder får och fastställer metoder brukar vi vanligtvis använda "set" i titeln och släppa "få". Hur du heter dina metoder är i slutändan upp till dig, men att släppa "få" är vanligt och hjälper till att undvika förvirring.
Vår nya uppsättning metoder ser så här ut:
// set metoder - (void) setVin: (NSNumber *) newVin; - (tomrum) setMake: (NSString *) newMake; - (tomrum) setModel: (NSString *) newModel; // bekvämlighet metod - (void) setMake: (NSString *) newMake andModel: (NSString *) newModel; // få metoder - (NSString *) göra; - (NSString *) modell; - (NSNumber *) vin;
Observera att de få metoderna använder samma namn som variablerna i klassen. Detta gör det enkelt när vi hämtar variablerna. Det kommer att vara som om vi har tillgång till variablerna direkt, vilket gör att metoderna i fången blir tydliga.
Så nu gränssnittet är på plats och vi vet vad klassen ska göra, måste vi genomföra våra metoder. Ser tillbaka, vi har fyra metoder som vi behöver implementera: setVin, setMake, setModel och setMake: andModel. Innan vi flyttar filer kopierar du metoddeklarationerna till ditt urklipp (Cmd + C). Stäng nu SimpleCar.h och skjut upp SimpleCar.m i redigeraren, klistra in metoddeklarationerna mellan @implementation och @end, så här:
@implementation SimpleCar // inställda metoder - (void) setVin: (NSNumber *) newVin; - (tomrum) setMake: (NSString *) newMake; - (tomrum) setModel: (NSString *) newModel; // bekvämlighet metod - (void) setMake: (NSString *) newMake andModel: (NSString *) newModel; // få metoder - (NSString *) göra; - (NSString *) modell; - (NSNumber *) vin; @slutet
Självfallet är detta inte rätt, så vad vi behöver göra är att byta halvkolonerna för krökta parentes där metodens inre verkningar kommer att gå, så här:
@implementation SimpleCar // set metoder - (void) setVin: (NSNumber *) newVin - (void) setMake: (NSString *) newMake - (void) setModel: (NSString *) newModel - setMake: (NSString *) newMake andModel: (NSString *) newModel // få metoder - (NSString *) gör - (NSString *) modell - (NSNumber *) vin @end
Nu behöver vi ge våra metoder lite kod. Låt oss börja med getter-metoderna, eftersom de är enkla. För varje getter-metod är allt vi behöver göra, se till att funktionen returnerar vad den är avsedd att returnera. Av denna anledning ser våra gettermetoder ut så här:
- (NSString *) gör return make; - (NSString *) modell returmodell; - (NSNumber *) vin return vin;
Kom ihåg: Metoderna returnerar de variabler vi definierade i gränssnittsfilen. Bli inte förvirrad mellan metodnamnen och de variabla namnen.
Det är ganska enkelt, när vi kallar make (till exempel), så returnerar pekaren till en NSString - i detta fall till make-variabeln. Samma händer för modell och vin (förutom naturligtvis returnerar vin ett tal).
Nu för setter metoderna, först ser vi koden och sedan går vi igenom det efteråt. Våra settermetoder ser ut så här:
// set metoder - (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 [modellversion]; modell = [[NSString allokera] initWithString: newModel]; // bekvämlighetsmetod - (tomrum) setMake: (NSString *) newMake andModel: (NSString *) newModel // Återanvända våra metoder från tidigare [self setMake: newMake]; [self setModel: newModel];
De angivna metoderna är lite knepigare än våra metoder. Vi vill fördela de värden som överförs till varje metod så att de ägs av klassen. Vi släpper först dessa variabler om de redan är tilldelade. Om de inte är allokerade, är de noll och negativa objekt ignorerar meddelanden som skickas till dem. Vi kommer att täcka dessa problem mer när vi diskuterar minneshantering.
Eftersom vi faktiskt tilldelade minne för våra föremål i setter-metoderna måste vi vara säkra på att vi släpper dem när objektet släpps från minnet. För att göra detta måste vi lägga till en anpassad deallokmetod, som så:
-(void) dealloc [vin release]; [frigöra] [modellversion]; [super dealloc];
grattis! Om du följde allt ovan bör du nu ha en arbetarklass (om inte, ladda ner källfilerna som är tillgängliga med den här artikeln). Så, låt oss testa det.
Öppna huvudfilen till ditt projekt (min heter CarApp.m) som som standard ska se något ut så här:
#importeraint main (int argc, const char * argv []) NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; // Sätt in anpassad kod här ... NSLog (@ "Hej, Värld!"); [poolavloppet]; returnera 0;
Ta bort kommentaren och NSLog-linjen eftersom vi inte behöver dem nu.
För att börja använda vår klass måste vi dra in det i programmet. Under den ursprungliga #import-raden lägg till följande rad:
#import "SimpleCar.h"
Vår klass är nu tillgänglig för användning, men vi måste skapa en instans av det för att testa det. Här är koden som används totalt:
#importera#import "SimpleCar.h" int main (int argc, const char * argv []) NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; SimpleCar * myCar = [[SimpleCar tilldela] init]; NSNumber * newVin = [NSNumber numberWithInt: 123]; [myCar setVin: newVin]; [myCar setMake: @ "Honda" ochModel: @ "Civic"]; NSLog (@ "Bilen är:% @% @", [myCar make], [myCar-modellen]); NSLog (@ "Vinen är:% @", [myCar vin]); [myCar release]; [poolavloppet]; returnera 0;
Först och främst skapar vi en pekare till en instans av SimpleCar som heter myCar. Därefter använder vi allokering och init - dessa kommer att diskuteras senare i raden.
Sedan vi behöver skicka en NSNummer till setVin-metoden, gör vi en här. Återigen skapar vi en pekare till en NSNumber-instans som heter newVin och vi initierar det med heltalet 123. Den konstanta "123" är ett heltal, varför vi använder numberWithInt.
Därefter anropar vi våra metoder, först och främst sätter vi vem som ska få meddelandet (myCar) och sedan använder vi metoden setVin. Efter kolon är det värde vi levererar till den metod som är den NSNumber vi skapade förut. Därefter gör vi detsamma men kallar setMake-metoden med två parametrar. Anledningen till att dessa parametrar föregås av ett @ -tecken är att berätta för kompilatorn att följande är en sträng.
Slutligen släpper vi ut myCar som vi är färdiga med - mer om detta senare i serien under minneshantering.
Vår klass arbetar nu, och för att se beviset lägger vi till några NSLog-satser för att skriva ut värdena till konsolen. Om du öppnar konsolen (Kör> Konsol) och sedan bygger och kör din app ska du se utdata som liknar detta:
Om du tittar på koden ovan, verkar det mycket meningslöst och överdriven. Till exempel, i våra getter-metoder är allt vi gör återvända en instansvariabel - men det tar upp tre streckkod för att göra något enkelt. Också i våra settermetoder ställer vi bara in instansvariabler - i huvudsak alla våra metoder, förutom vår metod som tar två argument, verkar uppblåst och i vägen. Objektiv-C löser detta med @property och @synthesize, som ersätter våra accessor-metoder och ger mycket bättre kodning.
Så här ser vår nya gränssnittsfil ut som att du använder egenskaper:
#importera@interface SimpleCar: NSObject NSString * make; NSString * modell; NSNumber * vin; @property (readwrite, behåll) NSString * make; @property (readwrite, behåll) NSString * -modell; @property (readwrite, behåll) NSNumber * vin; // bekvämlighet metod - (void) setMake: (NSString *) newMake andModel: (NSString *) newModel; @slutet
Wow, det är verkligen mycket kortare. Så vad händer med @property deklarationerna? Först berättar vi kompilatorn vi förklarar en egendom genom att använda @property, då följer vi med attribut för denna egendom. Attributen är läs / skriv status för en egenskap och lite minnehantering. Vi har använt readwrite för alla, vilket innebär att getter och setter-metoder skapas dynamiskt för våra instansvariabler (vi kan användas av skrivonly eller readonly för bara den ena eller den andra). Anledningen till att vi använder behållaren blir klar nästa gång vi täcker minneshantering.
Innan detta kan fungera måste vi implementera det i vår implementeringsfil, vi gör det här med @synthesize. Vår nya implementeringsfil ser så här ut:
#import "SimpleCar.h" @implementation SimpleCar @synthesize make, model, vin; - (tomrum) setMake: (NSString *) newMake andModel: (NSString *) newModel [self setMake: newMake]; [self setModel: newModel]; @slutet
Ser det inte bättre ut? Tänk på det här, @property ersätter alla gränssnittsmetoddeklarationer för getters och setters, och @synthesize ersätter själva metoderna själva. Getters och setters är nu dynamiskt skapade och vi behöver inte slösa tid på att skapa dem om vi inte behöver göra något riktigt speciellt.
Du bör nu ha ett fast grepp om klasser, föremål och instanser. Visst, du skapar inte klasser som ändrar världen ändå, men det här tar tid. Det är bättre att lära sig genom exempel, så om du inte kodar när du går med så var noga med att ladda ner källfilerna och läs igenom (och en kompilering) för att du är 100% på vad som händer.
Vi har nämnt minneshanteringen mycket i den här handledningen, det är ett mycket viktigt ämne som behöver åtgärdas (pun intended), så vi dyker in till den nästa gången. Det är sant att det inte är det roligaste ämnet eller det enklaste att komma till rätta med, men det är absolut nödvändigt om du vill bli en skicklig Målare-C programmerare.
Den här veckans utmaning kan vara lite knepig, men vi får se hur du går vidare. Först och främst, om du inte har kopierat hela koden ovan, ladda ner källfilerna som ingår i den här artikeln. Utmaningen är att lägga till en annan klass i projektet, men den här gången borde det vara en underklass av SimpleCar (kom ihåg, vi definierar förälderklassen i gränssnittsfilen). Om du kan göra det, leker du om och använder de ärvda metoderna och försöker lägga till egna saker som: motorstorlek, dörrar eller höjd.
Kom ihåg: Om du har några frågor eller frågor, släpp en kommentar nedan eller skjut mig ett meddelande på Twitter. Den enda dumma frågan är den du inte frågade - den här serien handlar om att lära dig, så gärna fråga dig!