Alla IOS-appar som utvecklas måste använda åtminstone en liten gnutta Objective C, och de flesta använder nästan enbart detta programmeringsspråk. Men vad är det och hur funkar det?
I första delen i vår artikelserie om #IOS-utveckling installerade vi Apples utvecklingsmiljö #Xcode, testade att köra en app i simulatorn, och tog en första titt på hur du med hjälp av Xcodes grafiska gränssnitt och så kallade Storyboards enkelt kan börja bygga upp ett gränssnitt för en app med minimalt antal rader kod.
Egen kod kommer du i enklare appar till huvuddelen att skriva för att hantera data och återkoppla till gränssnittet efter händelser baserade på datan och användarens inmatningar.
Den här gången ska vi börja titta på hur programmeringsspråket #Objective C är uppbyggt och hur du ska tänka när du skapar dina egna klasser och metoder. Apple har lagt ner ett enormt arbete på att systematisera och göra denna programmering så intuitiv och förståelig det går, och detta är något du bör utnyttja.
Om du redan kan en del programmering som du lärt dig i ett annat språk kommer du att känna igen strukturer som if/then och for-loopar, liksom datastrukturer som listor (array) och textsträngar. Men du kommer behöva lära dig ett nytt sätt att tänka ändå, och försök inte att hålla fast vid något inlärt, ”beprövat”, sätt att lägga upp din kod – det blir helt enkelt mycket lättare om du följer Apples exempel.
Du har säkert hört termen objektorienterad programmering eller objektorienterat programmeringsspråk – C++, Objective C och Java tillhör denna kategori medan till exempel C och Pascal är så kallade procedurella programmeringsspråk. Men vad betyder detta egentligen?
Det har skrivits tjocka luntor om vad objektorienterat innebär, det är uppenbarligen inte det lättaste av ämnen att greppa, men om vi grovt förenklar det hela handlar det om hur olika delar av koden förhåller sig till varandra och kanske framför allt hur du ser det sammanhängande programmet i ditt inre.
I ett objektorienterat språk består ett program av en mängd – från en handfull till tusentals – objekt. Varje objekt har en viss struktur som bestäms av något som kallas en klass. Ungefär som att varje människa tillhör arten Homo Sapiens och varje lax är ett ”objekt” av ”klassen” Salmo Salar.
I ett fiskarspel kan det mycket väl finnas en klass som heter till exempel NNMFiskSalmoSalar och beskriver en standardlax. Klasser bygger nästan alltid på andra klasser som i sin tur bygger på en annan klass – på så sätt skapas en struktur av klasser så att du slipper lägga till grundläggande funktionalitet i varje ny klass du skapar.
I vårt exempel finns till exempel förmodligen en NNMFisk-klass som beskriver fiskar i allmänhet. På så sätt ärver (inherits på engelska, ett uttryck du säkerligen kommer stöta på när du läser vidare på egen hand) NNMFiskSalmoSalar och NNMFiskEsoxLucius (gädda, om du undrade) alla grundläggande egenskaper för fiskar, men har sedan sina egna unika egenskaper.
Du lade säkert märke till den märkliga stavningen av klassnamnen ovan, och de ser inte ut så av en slump. Apple rekommenderar vad som kallas "Camel Case" på engelska – att skriva ihop alla orden i namnet och göra första bokstaven i varje stor, så att det ser ut som pucklarna på en kamel. De första tre bokstäverna är ett prefix du själv hittar på. Det kan till exempel vara en kortform av ditt namn eller namnet på just den app du just nu bygger, men tanken är att du direkt ska känna igen en klass som du själv har skapat.
I Xcode kan du bygga vanliga IOS-appar med hjälp av Storyboards. Här kan du se hur olika vyer (Views) och kontrollobjekt (ViewControllers) sitter ihop med varandra. Metoder, det vill säga de olika funktioner som du ger en klass, ska också skrivas på samma sätt, men där inleds det första ordet med liten bokstav istället. Om du kommer ihåg från första delen i artikelserien lade vi till en rad kod i en metod kallad:
-(IBAction)tryckaKnappen:(id)sender { }
Den här formen har alla metoder i det som kallas klassens implementation. Beskrivningen av en klass består alltid av två delar: Ett interface och en implementation. I den föregående beskrivs vad som ingår och vad objekt av andra klasser ”vet” om objekt av klassen i fråga. När du jobbar med Apples olika ramverk kan du läsa de många klassernas interface-filer, men inte deras implementationer.
En metod är ett stycke kod som utför en viss funktion, vilket kan vara allt från något så enkelt som att ta ändra ett värde på en variabel till avancerade beräkningar. I den app vi gjorde i del ett gjorde vår nya metod tryckaKnappen att texten på en etikett ändrades.
Olika objekt i ett objektorienterat program kommunicerar med varandra genom att skicka meddelanden. I Objective C följer detta ett mönster som ser ut så här:
[mottagare meddelandeTyp:innehåll];
Mottagaren är det objekt du vill skicka ett meddelande till, meddelandeTyp är namnet på en metod som mottagaren har tillgång till (som beskrivs av dess klass eller av en av de klasser den ärver ifrån).
Innehåll är någon typ av data som utgör själva meddelandet. I många fall blir det väldigt invecklat att följa den här standarden, och därför har Objective C även ett annat sätt att skriva ut meddelanden, med så kallad punktnotation.
I vår app från förra artikeln i denna serie såg du följande meddelande:
self.etikett.text = @"Hej du!";
Detta är exakt samma sak som att skriva:
[[self etikett] setText:@”Hej du!”];
Verkar det förvirrande? Kanske, men du ska se att det inte är så komplicerat egentligen.
"Self" i Objective C är ett slags kodord för objektet självt. Du kommer ofta behöva skicka meddelanden från en metod i en klass till en annan, och då används ofta en referens till self för att mena just det objekt som skickar meddelandet.
"[self etikett]" betyder att vi skickar ett innehållslöst meddelande av typen etikett till objektet self. Vad innebär det då? Jo, när du bygger in en variabel i en klass i Objective C är det vanligt att du gör det via något som kallas en @property. Dessa är både en variabel och två automatiskt framtagna metoder som ger åtkomst till variabeln för andra objekt – en metod skickar tillbaka värdet på variabeln som svar och den andra tar emot ett nytt värde och ändrar variabeln till detta. [self etikett] är alltså ett meddelande som får ett svar i form av variabeln bakom etikett.
Skriver du self.etikett tolkas det antingen som "[self etikett]" eller "[self setEtikett]" beroende på sammanhanget och du behöver inte bekymra dig om hur det fungerar.
setText:@”Hej du!” är ett meddelande med innehållet @”Hej du!” av typen setText. Det senare är just en sådan automatiskt framtagen metod för att ändra en variabel som vi nyss nämnde. Formen @”Hej du!” är det sätt på vilket du skriver in en textsträng så att Xcode förstår att det är just det.
Att du antingen kan skriva self.etikett.text eller [[self etikett] setText:text] beror på att Apple har lagt till en smart funktion i kompilatorn som översätter det föregående sättet att skriva till det senare.
I korthet fungerar alla Objective C-program genom att en mängd olika objekt tillhörande olika klasser skickar meddelanden fram och tillbaka till varandra. Nya objekt skapas genom att du skickar ett meddelande om att skapa ett nytt objekt till dess klass – klasserna själva är faktiskt också objekt, men om det känns som att det går över ditt förstånd är du inte ensam och det är inget du egentligen behöver förstå på ett djupare plan.
Så här skapas till exempel en ny, tom lista (array) som vi kan fylla på med nya objekt:
NSMutableArray *minLista = [[NSMutableArray alloc] init];
Det vänstra ledet är helt enkelt en definition: Här är ett nytt objekt som heter minLista och har klassen NSMutableArray. Stjärnan krävs för alla variabler som är objekt. Det är bara när du har att göra med icke-objekt som rena tal du inte skriver med stjärnan.
Till höger ser du samma form som ovan: [NSMutableArray alloc] skickar det innehållslösa meddelandet alloc till objektet NSMutableArray – här ser du hur en klass själv är ett objekt – och resultatet som kommer tillbaka är just ett nytt objekt av den klassen. Sedan skickas det innehållslösa meddelandet init till detta nya objekt, vilket är en standardmetod för att ge ett nytt objekt grundläggande värden på sina variabler.
En av de fina sakerna med den här programmeringsmodellen är att du, när du har att göra med klasser som andra har utvecklat, aldrig behöver veta hur dessa fungerar under ytan – vad som faktiskt händer när du skickar init varierar stort mellan olika klasser, men är helt ointressant för dig när du gör ett nytt objekt. På samma sätt behöver du inte veta hur setText fungerar när du ska ändra text på en etikett, allt du behöver veta är vilken form innehållet på meddelandet ska ha och vad meddelandet är till för, och det kommer oftast av sig själv tack vare den intuitiva namngivningstmodellen i Objective C.
En illustration över hur olika objekt kan hänga ihop i ett objektorienterat program.
Föraren i bilen är ett objekt av klassen Driver. Den har olika attribut i form av variabler (Hur duktig förare är den? Hur mycket har den druckit? Hur ser den ut?).
Om spelaren vrider sin Iphone åt vänster kommer en osynlig klass som styr bilen att styra den åt vänster. Om det är en realistisk simulering kan det innebära att ratten i bilen vrids åt vänster, vilket i sin tur får ratten att meddela hjulen att de ska vridas åt vänster. En sådan händelsekedja är vanlig. IOS tar emot dina pekningar på skärmen, som skickas till det aktiva programmet, som skickar meddelandet om beröringen vidare först till fönstret som skickar det till den aktiva ViewControllern, som i sin tur… och så vidare.
Hjulen i vårt avancerade bilspel har variabler som lufttryck, friktionskoeffecient och liknande. Varje hjulobjekt kan ha olika värden på dessa utifrån hur de har påverkats under spelets gång, och varje hjulobjekt tar emot meddelanden som ”vrid åt höger” och ”du har just kört över en grävling” – vad dessa saker gör med hjulet behöver de objekt som skickar meddelandena, i vårt fall Ratten respektive objektet Miljön eller kanske Vägen, inte bry sig om.
Själva bilen är ett slags paraplyobjekt som har många ”barn” – objekt som är kopplade till den – och har själv variabler som hastighet, utseende, årsmodell och tillverkare.
Strålkastarna är från resten av programmet sett väldigt enkla objekt – på eller av, samt fungerande eller trasiga är i princip det enda något annat objekt kommer behöva veta. Hur den fungerar internt är dolt.
Bilen består så klart av många fler objekt, många som bara är ”rekvisita” och andra som kan styras av andra delar eller i sin tur styra något annat.
Detta har så klart bara varit en väldigt grundläggande titt på hur Objective C fungerar och är uppbyggt, men vi hoppas att det har gett en viss förståelse och kanske gör det lättare att hänga med i mer invecklade förklaringar om du fortsätter förkovra dig och läser mer.
De allra flesta böcker om IOS-utveckling tar antingen för givet att du redan har ett hum om hur ”vanlig” programmering med C fungerar och utgår från det, eller struntar helt i att försöka förklara tanken bakom den grundläggande strukturen i språket.
Är du genast sugen på att läsa mer kan du ta en titt i vår litteraturlista nedan. Apples egna guider är förvånansvärt välskrivna, men går också rakt på sak och inte särdeles nybörjarvänliga.
Nästa lördag kavlar vi tillsammans upp ärmarna och tar tag i att bygga en app som faktiskt gör något mer än bara säger hej.
Object-Oriented Programming with Objective-C – om du vill veta mer om filosofin bakom objektorienterad programmering ur Apples synvinkel. PDF hos Apple.
Learning Objective-C: A Primer – om du redan kan en del C och/eller C++ kan du ta en titt på denna ”snabbguide” till Objective C. PDF hos Apple.
Programming with Objective-C – Apples stora guide till Objective C-språket, med allt du behöver veta för att kunna förstå hur själva koden fungerar.
Guiden lär dig ingenting om utveckling för iOS, men är ändå en bra bok att ha till hands. Prova att läsa
igenom den och se hur mycket du förstår redan nu, och återkom senare när du har börjat lära dig mer. PDF hos Apple.
Programming in Objective-C (5th Edition) av Stephen Kochan – den verkliga ”bibeln” när det kommer till grundkunskaper i Objective C.