Welkom bij deel vier van deze serie over Objective-C. Tot nu toe hebben we veel gekeken naar de theorie en de principes en functionaliteit van de taal om een goed idee te krijgen van hoe het werkt. Vandaag gaan we een eenvoudige les maken die vergelijkbaar is met het autovoorbeeld dat we in eerdere delen van deze serie hebben bekeken. Onze klas zal de details van een auto nemen, zodat we de waarden kunnen vastleggen en vastleggen. Na het voorbeeld van vandaag zou je in staat moeten zijn om je eigen klassen in Xcode te creëren en ermee te spelen.
Tot nu toe hebben we geweldige feedback gehad via e-mail, twitter en reacties. Het is geweldig om te zien dat zoveel mensen geïnteresseerd zijn in dit onderwerp en het is nog beter om te zien dat zoveel van jullie het zelf uitproberen en een paar geweldige vragen stellen. Ga zo door!
Begin met het starten van Xcode en het maken van een nieuw project. Klik onder het Mac OS X-scheidingsteken op Toepassing en klik vervolgens op het opdrachtregelhulpprogramma. Wijzig tot slot de vervolgkeuzelijst om het type in te stellen op Foundation.
Bewaar het project zoals je wilt, ik heb mijn CarApp gebeld. Zodra het projectvenster verschijnt, moeten we een nieuwe klasse maken. Raak Command-N (of Bestand> Nieuw bestand), navigeer naar Cocoa Class onder Mac OS X en selecteer Objective-C-klasse. Zorg ervoor dat Subklasse van is ingesteld op NSObject en klik op Volgende. Geef uw klasse SimpleCar een naam en zorg ervoor dat er een .h-bestand wordt aangemaakt en sla het op.
Onze klas bestaat nu, maar hij doet niets. Laten we dat veranderen door het een code te geven. Vergeet niet dat we in Objective-C onze code in twee delen hebben verdeeld: interface en implementatie. Het is logisch om eerst aan de interface te werken, dus daar beginnen we aan.
Open het bestand SimpleCar.h en in de huidige staat zou het er zo uit moeten zien (ik heb de commentaarkop hieronder weggelaten)
#importeren@interface SimpleCar: NSObject @end
Allereerst zijn we inclusief Cocoa.h, waarmee we toegang krijgen tot zaken als NSString, NSMutableString, enzovoort. Vervolgens maken we onze klasse (SimpleCar) als een subklasse van NSObject.
Nu moeten we beslissen welke informatie onze klas nodig heeft om op te slaan. Aangezien we een auto als voorbeeld gebruiken, moeten we autogerelateerde informatie opslaan, zoals:
Er is nog veel meer waar we naar toe kunnen gaan, maar voorlopig is dat genoeg. Voor elk van deze eigenschappen moeten we ze opslaan in een variabele die geschikt is voor dat type gegevens. Merk en model zijn een reeks tekens (zoals tekst, nummer en mogelijk interpunctie), dus het is logisch om een tekenreeks te gebruiken. Het VIN (Vehicle Identification Number) is alleen een nummer, dus dat is wat we zullen gebruiken. Onze code ziet er nu als volgt uit (header weggelaten):
@interface SimpleCar: NSObject NSString * make; NSString * -model; NSNumber * vin; @end
We hebben eerder gezegd dat een methode moet worden gebruikt om gegevens uit een klasse te krijgen of in te stellen. Dus om de variabelen in te stellen, moeten we methoden toevoegen. Om dit te doen, maken we er vier: een zal het merk instellen, een het model, een het VIN, en een laatste methode zal zowel het EN-model instellen (alleen om je te laten zien hoe je meerdere argumenten gebruikt).
@interface SimpleCar: NSObject NSString * make; NSString * -model; NSNumber * vin; // stel methodes in - (void) setVin: (NSNumber *) newVin; - (void) setMake: (NSString *) newMake; - (void) setModel: (NSString *) setModel; // gemaksmethode - (ongeldig) setMake: (NSString *) newMake andModel: (NSString *) newModel; @einde
We declareren methoden na de accolade en vóór @end. Door een streepje (minteken) vóór de methode te plaatsen, vertellen we de compiler dat we op het punt staan een exemplaarmethode te declareren. Een instantiemethode is een methode die wordt uitgevoerd op ons exemplaar. Omgekeerd geeft een plusteken aan dat de methode die wordt opgeroepen een klassemethode is waarvoor geen afzonderlijke objectinstantie hoeft te worden uitgevoerd, meer later hieromtrent.
Onze eerste methode retourneert ongeldig, heet setVin en neemt een NSNumber als argument. Onze tweede methode is vergelijkbaar, retourneert ongeldig, is call setMake en neemt een NSString als argument. De derde is hetzelfde, met een andere naam.
Onze laatste methode retourneert ook ongeldig maar neemt twee parameters in: newMake en newModel, die beide NSString zouden moeten zijn. De naamgeving die in deze methode wordt gebruikt, is vergelijkbaar met de manier waarop de meeste Objective-C-methoden worden genoemd: in gewoon Engels. Dus als je de toegestane methode leest, is het duidelijk dat de methode "Merk en model instellen" is. Het is belangrijk om te onthouden dat de methode naam in dit geval 'setMake: andModel:' is - alle argumenttitels zijn opgenomen in de methode naam.
Een belangrijke opmerking is dat we (ongeldig) gebruiken omdat onze methoden niets hoeven terug te geven. Omdat het enige wat ze doen het instellen van gegevens is en niets terug hoeft te sturen (zoals een succesbericht) gebruiken we eenvoudig ongeldig.
Vervolgens voegen we de methoden toe die we gebruiken om de waarden te verkrijgen. Hoewel we onze methoden voor het ophalen en instellen van methoden noemen, gebruiken we meestal alleen 'set' in de titel en laten we 'ophalen' weg. Hoe u uw methoden noemt, is uiteindelijk aan u, maar 'halen' is gewoon en helpt verwarring voorkomen.
Onze nieuwe set van methoden ziet er als volgt uit:
// set methods - (void) setVin: (NSNumber *) newVin; - (void) setMake: (NSString *) newMake; - (void) setModel: (NSString *) newModel; // gemaksmethode - (ongeldig) setMake: (NSString *) newMake andModel: (NSString *) newModel; // haal methodes - (NSString *) aan; - (NSString *) model; - (NSNumber *) vin;
Merk op dat de get-methoden dezelfde namen gebruiken als de variabelen in de klasse. Dit maakt het eenvoudig als we de variabelen ophalen. Het zal zijn alsof we rechtstreeks toegang tot de variabelen hebben, waardoor de get-methoden transparant worden.
Dus nu de interface op zijn plaats is en we weten wat de klas gaat doen, moeten we onze methoden implementeren. Als we terugkijken, hebben we vier methoden die we moeten implementeren: setVin, setMake, setModel en setMake: andModel. Voordat we bestanden verplaatsen, kopieert u de methodeaangiften naar uw klembord (Cmd + C). Sluit nu SimpleCar.h en start SimpleCar.m in de editor en plak de methodeaanduidingen tussen de @implementation en @end, zoals:
@implementation SimpleCar // stel methoden in - (void) setVin: (NSNumber *) newVin; - (void) setMake: (NSString *) newMake; - (void) setModel: (NSString *) newModel; // gemaksmethode - (ongeldig) setMake: (NSString *) newMake andModel: (NSString *) newModel; // haal methodes - (NSString *) aan; - (NSString *) model; - (NSNumber *) vin; @einde
Uiteraard klopt dit niet, dus wat we moeten doen is de puntkomma verwisselen voor accolades waar de innerlijke werking van de methode zal gaan, zoals deze:
@implementation SimpleCar // stel methoden in - (void) setVin: (NSNumber *) newVin - (void) setMake: (NSString *) newMake - (void) setModel: (NSString *) newModel - (void) setMake: (NSString *) newMake andModel: (NSString *) newModel // get methods - (NSString *) make - (NSString *) model - (NSNumber *) vin @end
Nu moeten we onze methoden wat code geven. Laten we beginnen met de gasvangermethoden, omdat ze eenvoudig genoeg zijn. Voor elke methode van de getter is alles wat we moeten doen ervoor zorgen dat de functie retourneert wat de bedoeling is om terug te keren. Om deze reden zien onze gettersystemen er als volgt uit:
- (NSString *) maakt return make; - (NSString *) model retourmodel; - (NSNumber *) vin return vin;
Onthouden: de methoden retourneren de variabelen die we in het interfacebestand hebben gedefinieerd. Raak niet in de war tussen de methodenamen en de variabelenamen.
Dat is vrij eenvoudig, wanneer we make (bijvoorbeeld) aanroepen, dan geeft dit de aanwijzer naar een NSString - in dit geval naar de make-variabele. Hetzelfde gebeurt voor model en vin (behalve dat vin een getal teruggeeft).
Nu voor de methode van de setter, zullen we eerst de code bekijken en daarna gaan we er doorheen. Onze settermethoden zien er als volgt uit:
// 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 [model release]; model = [[NSString alloc] initWithString: newModel]; // gemaksmethode - (ongeldig) setMake: (NSString *) newMake enmodel: (NSString *) newModel // Hergebruik onze methoden van vroeger [self setMake: newMake]; [self setModel: newModel];
De ingestelde methoden zijn een beetje lastiger dan onze methoden. We willen de waarden die worden doorgegeven aan elke methode toewijzen, zodat ze eigendom zijn van de klas. We geven eerst deze variabelen vrij in het geval ze al zijn toegewezen. Als ze niet zijn toegewezen, zijn ze nul en negeren objecten berichten die aan hen zijn doorgegeven. We zullen deze kwesties meer behandelen als we het over geheugenbeheer hebben.
Omdat we in de settermethoden feitelijk geheugen hebben gereserveerd voor onze objecten, moeten we zeker weten dat we ze vrijgeven wanneer het object uit het geheugen wordt vrijgegeven. Om dit te doen, moeten we een aangepaste dealloc-methode toevoegen, zoals:
-(void) dealloc [vin release]; [maak vrijgave]; [model release]; [super dealloc];
Gefeliciteerd! Als je alles hierboven hebt gevolgd, zou je nu een werkende klasse moeten hebben (als dit niet het geval is, download dan de bronbestanden die bij dit artikel beschikbaar zijn). Dus laten we het uittesten.
Open het hoofdbestand van uw project (de mijne wordt CarApp.m genoemd) die er standaard zo zou moeten uitzien:
#importerenint main (int argc, const char * argv []) NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; // Voeg hier de aangepaste code in ... NSLog (@ "Hello, World!"); [afvoer zwembad]; retourneer 0;
Verwijder de opmerking en NSLog-regel, want we hebben ze nu niet nodig.
Om onze klas te gaan gebruiken, moeten we hem in het programma opnemen. Onder de oorspronkelijke regel #import voegt u de volgende regel toe:
#import "SimpleCar.h"
Onze klas is nu beschikbaar voor gebruik, maar we moeten er een exemplaar van maken om hem uit te testen. Hier is de code die in totaal wordt gebruikt:
#importeren#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 (@ "De auto is:% @% @", [myCar make], [myCar-model]); NSLog (@ "De vin is:% @", [myCar vin]); [myCar-release]; [afvoer zwembad]; retourneer 0;
Eerst en vooral maken we een aanwijzer naar een instantie van SimpleCar genaamd myCar. Vervolgens gebruiken we alloc en init - deze worden verderop in de regel besproken.
Omdat we nu een NSNumber moeten doorgeven aan de setVin-methode, maken we er hier een. We maken opnieuw een pointer naar een NSNumber instantie genaamd newVin en we initiëren dit met de integer waarde van 123. De constante '123' is een geheel getal, daarom gebruiken we numberWithInt.
Vervolgens roepen we onze methoden op, in de eerste plaats plaatsen we wie de boodschap moet ontvangen (myCar) en dan gebruiken we de methode setVin. Na de dubbele punt is de waarde die we leveren aan de methode die de NSNumber is die we eerder hebben gemaakt. Vervolgens doen we hetzelfde, maar noemen we de setMaak-methode met twee parameters. De reden dat deze parameters worden voorafgegaan door een @ -teken, is om de compiler te laten weten dat het volgende een tekenreeks is.
Ten slotte geven we myCar vrij, omdat we ermee klaar zijn. Hierover later in de serie onder geheugenbeheer.
Onze klas werkt nu en om het bewijs te zien, hebben we een aantal NSLog-instructies toegevoegd om de waarden naar de console af te drukken. Als u de console opent (Uitvoeren> Console) en vervolgens uw app bouwt en uitvoert, ziet u de uitvoer als volgt:
Als je de bovenstaande code bekijkt, lijkt veel ervan vrij zinloos en overdreven. In onze gettermethoden bijvoorbeeld, is het enige wat we doen het retourneren van een instantievariabele - maar dit neemt drie regels code in beslag om iets simpels te doen. Ook stellen we in onze methode voor het instellen van instanties instantinstitutievariabelen in - in wezen al onze methoden, behalve onze methode die twee argumenten vereist, die opgeblazen en in de weg zitten. Objective-C lost dit op met @property en @synthesize, die onze accessormethoden vervangen en zorgen voor veel nettere codering.
Dit is hoe ons nieuwe interface-bestand eruit ziet met behulp van eigenschappen:
#importeren@interface SimpleCar: NSObject NSString * make; NSString * -model; NSNumber * vin; @property (readwrite, retain) NSString * make; @property (readwrite, retain) NSString * -model; @property (readwrite, retain) NSNumber * vin; // gemaksmethode - (ongeldig) setMake: (NSString *) newMake andModel: (NSString *) newModel; @einde
Wauw, dat is echt een stuk korter. Wat gebeurt er met de @property-aangiften? Eerst vertellen we de compiler dat we een eigenschap declareren met @property, dan volgen we met attributen voor deze eigenschap. De kenmerken zijn de lees- / schrijfstatus van een eigenschap en enig geheugenbeheer. We hebben readwrite voor allemaal gebruikt, wat betekent dat getter- en settermethoden dynamisch worden gemaakt voor onze instantievariabelen (we kunnen het alleen of alleen gebruiken). De reden dat we behouden blijven gebruiken, zal de volgende keer duidelijk worden wanneer we geheugenbeheer behandelen.
Voordat dit kan werken, moeten we het implementeren in ons implementatiebestand, we doen dit met @synthesize. Ons nieuwe implementatiebestand ziet er als volgt uit:
#import "SimpleCar.h" @implementation SimpleCar @synthetiseren make, model, vin; - (void) setMake: (NSString *) newMake andModel: (NSString *) newModel [self setMake: newMake]; [self setModel: newModel]; @end
Ziet dat er niet beter uit? Zie het zo: @property vervangt alle declaraties van de interfacemethode voor getters en setters en @synthesize vervangt de feitelijke methoden zelf. De getters en setters zijn nu dynamisch gemaakt en we hoeven geen tijd te verspillen met het maken ervan, tenzij we iets heel bijzonders moeten doen.
Je zou nu een stevige greep moeten hebben op klassen, objecten en instanties. Natuurlijk, je maakt geen lessen die de wereld nog zullen veranderen, maar dit spul kost tijd. Het is beter om het voorbeeld te leren, dus als u niet codeert terwijl u doorgaat, zorg er dan voor dat u op zijn minst de bronbestanden downloadt en doorleest (en compileert) om ervoor te zorgen dat u 100% tevreden bent over wat er gebeurt.
We hebben het beheer van geheugen vaak genoemd in deze tutorial, het is een heel belangrijk onderwerp dat moet worden aangepakt (pun intended), dus daar duiken we de volgende keer weer in. Het is waar, het is niet het leukste onderwerp of het gemakkelijkst om mee om te gaan, maar het is absoluut cruciaal als je een ervaren Objective-C-programmeur wilt worden.
De uitdaging van deze week is misschien een beetje lastig, maar we zullen zien hoe je verder gaat. Allereerst downloadt u de bronbestanden die bij dit artikel zijn opgenomen als u niet alle bovenstaande code hebt gekopieerd. De uitdaging is om nog een klasse aan het project toe te voegen, maar deze keer zou het een subklasse van SimpleCar moeten zijn (onthoud, we definiëren de ouderklasse in het interfacebestand). Als je dat kunt doen, speel dan rond en gebruik de overgeërfde methodes en probeer je eigen toe te voegen voor dingen zoals: motorgrootte, deuren of hoogte.
Onthouden: als je vragen of vragen hebt, kun je hieronder een reactie achterlaten of een bericht op Twitter schieten. De enige stomme vraag is degene die je niet hebt gesteld - deze serie gaat over leren dus voel je vrij om af te vragen!