Med grunderna i C fortfarande fräscha i ditt minne är det dags att bli bekant med Objective-C. Huvudskillnaden med C är att Objective-C är ett objektorienterat programmeringsspråk, medan C är ett procedurprogrammeringsspråk. Det innebär att vi först måste förstå föremål och hur de relaterar till klasser. Andra nyckelbegrepp som vi kommer att undersöka i denna artikel är objektmeddelanden, inkapsling och arv.
Mål-C och Kakao är två huvudkomponenter i IOS-plattformen. Trots att IOS-plattformen fortfarande är relativt ung, skapades Objective-C i början av 1980-talet på StepStone av Brad Cox och Tom Love. Språket skapades för att kombinera det robusta och smidiga C-programmeringsspråket med det eleganta Smalltalk-språket. Objektiv-C är en strikt superset av C och, i motsats till C, är det ett högtalande programmeringsspråk. Huvudskillnaden mellan C och Objective-C är att den senare är ett objektorienterat programmeringsspråk, medan C är ett procedurprogrammeringsspråk.
Hur slutade iOS med ett språk som utvecklades på 1980-talet? Kort efter att NeXT grundades av Steve Jobs licensierades det Objective-C från StepStone. NeXT skapade NeXTSTEP, ett verktyg för användargränssnitt för NeXT-operativsystemet utvecklat i Objective-C. Trots att NeXTSTEP tillhandahöll en revolutionerande uppsättning verktyg, fick NeXT-operativsystemet endast lite dragkraft på marknaden. 1996 förvärvade Apple NeXT och NeXTSTEP blev kakao. Den sistnämnda gick vanligt med introduktionen av OS X i mars 2001 och senare med utgåvan av iPhone och iOS-operativsystemet.
I procedurprogrammering består ett program av en serie procedurer eller rutiner som exekveras för att nå ett visst tillstånd. I objektorienterad programmering, emellertid, en samling objekt samverkar och arbetar tillsammans för att slutföra en uppgift. Även om slutresultatet kan vara identiskt, är metodiken och underliggande paradigmer väsentligen olika. Modularitet och kodåteranvändning är två av de främsta fördelarna med objektorienterade programmeringsspråk som vi snart kommer att se.
Utvecklare som är nya i iOS- och OS X-ekosystemen blir ofta förvirrade av förhållandet mellan Objective-C, Cocoa (OS X) och Cocoa Touch (iOS). Vad är Cocoa Touch och hur är det relaterat till Objective-C? Kakao är Apples ursprungliga applikationsprogrammeringsgränssnitt (API) för iOS- och OS X-plattformarna. Mål-C är språket som driver kakao. Medan den här artikeln huvudsakligen fokuserar på målprogrammets språk, kommer vi att se närmare på Cocoa and Cocoa Touch API-seriens senare serie.
Ett annat hinder för utvecklare som är ny för att objektorienterad programmering är skillnaden mellan klasser, objekt och instanser. En klass är en gjutning eller en ritning för att skapa objekt, medan instanser är unika förekomster av en klass. Ett objekt är en datastruktur som har en stat och ett beteende. Trots den subtila skillnaden mellan objekt och instanser används båda termerna ofta utbytbart.
Låt oss ta en titt på ett exempel: brödrostar. Innan en brödrost tillverkas skapar ingenjörer en ritning, som motsvarar en klass. Varje brödrost som skapas från ritningen är en förekomst eller en unik förekomst av klassen. Även om varje brödrost är skapad från samma ritning (klass), har de varje sin egen stat (färg, antal slitsar etc.) och beteende.
Instansens tillstånd lagras i och definieras av dess instansvariabler, eller objektets attribut om du vill. Detta ger oss ett annat viktigt mönster av objektorienterad programmering: inkapsling. Inkapsling innebär att den inre representationen av ett objekt är privat och endast känd för själva objektet. Det här kan verka som en allvarlig begränsning vid första anblicken. Resultatet är emellertid modulär och löst kopplad kod.
Låt oss illustrera inkapsling med ett annat exempel. Bilens hastighet mäts av bilens inre, men föraren känner till bilens hastighet genom att titta på hastighetsmätaren. Föraren behöver inte veta om eller förstå bilens internals för att känna till bilens hastighet. På samma sätt behöver bilens förare inte förstå hur motorer arbetar för att kunna köra bilen. Detaljerna om hur en bil fungerar är dold från föraren. Bilens tillstånd och beteende är gömd från föraren och är tillgänglig genom bilens gränssnitt (ratt, bromspedal, instrumentpanel etc.).
Ett annat kraftfullt paradigm med objektorienterad programmering är klassärv. När klass A är a underklass av klass B, förvärvar klass A attributen och beteendet för klass B. Klass B sägs vara förälderklassen eller överklassen i klass A. Erfarenhet främjar även kodåteranvändning och modularitet.
Metoder är subrutiner associerade med en klass och de definierar beteendet hos en klass och dess instanser. Metoderna i en klass har tillgång till en instans internaler och kan därigenom modifiera instansens tillstånd. Med andra ord, tillståndet hos en instans (dvs instansvariabler) styrs av metoderna för en förekomst (dvs exempel metoder).
På grund av inkapslingsmönstret kan instansvariablerna i en klassinstans inte nås fritt. Istället är de åtkomliga genom getters och sett, metoder med det enda syftet att få och ställa in instansvariabler. Egenskaper är en funktion av Objective-C som gör skapandet av accessors (getters och setters) trivial. Trots användarnas användbarhet blir det snabbt besvärligt att skriva accessor metoder för varje instansvariabel. Vi kommer att undersöka egenskaper mer i detalj senare i den här artikeln. För närvarande, överväga egenskaper som wrappers kring instansvariabler som gör det lättare att arbeta med instansvariabler genom getters och setters.
Låt oss utöva vår kunskap genom att skapa ett nytt Xcode-projekt att arbeta med. Skapa ett nytt projekt i Xcode genom att välja Nytt> Projekt ... från Fil meny.
Som vi gjorde i föregående artikel, välj Kommandoradsverktyg projektmall i Ansökan kategori under OS X sektion.
Ställ in produktnamn till Böcker och ge projektet ett organisationsnamn och företagsidentifierare. För detta projekt är det viktigt att ställa in projekttypen till fundament. Anledningen till detta val kommer att bli tydlig senare i den här artikeln.
Berätta Xcode där du vill spara projektet och klicka på Skapa knapp. Du kanske märker att projektet ser annorlunda än det projekt vi skapade för att lära C. Klockan tar en stund att se vad skillnaderna är.
Projektet innehåller några fler filer och mappar än kommandoradsverktyget som vi skapade i föregående artikel. Dessutom main.m och Books.1, Det finns två nya mappar, Stödja filer och ramar, var och en innehåller ett objekt.
Stödja filer innehåller en fil som heter Books-Prefix.pch. De .PCH filtillägg berättar för oss att detta är en förkompilerade headerfilen. Dess syfte kommer att bli tydlig senare i denna serie.
De ramar mappen innehåller de ramar som projektet är kopplat till. Vad är en ram? En ram är en bunt eller katalog som innehåller ett bibliotek med dess resurser, till exempel bilder och huvudfiler. Konceptet med en headerfil kommer att bli klar på bara en minut. De ramar mappen innehåller för närvarande ett objekt, Foundation.framework.
När du skapar projektet ställer du in projekttypen till fundament, vilket innebär att projektet är kopplat till stiftelsens ramverk. Stiftelsens ramverk är en grundläggande uppsättning mål-C-klasser. Senare i denna serie kommer vi att se närmare på stiftelsens ramverk.
Det är dags att skapa din första klass. När du skapar en ny fil (Fil> Ny> Fil ... ), presenteras en lista med filmallar. Välja Kakao från OS X avsnitt och välj Mål-C-klass mall för att skapa en ny mål-C-klass. Klick Nästa att fortsätta.
Ge den nya klassen ett namn på bok
och ställa in sin underklass till NSObject
. Som vi såg tidigare, genom att göra den nya klassen en underklass av NSObject
, den nya klassen kommer att arva attributen och beteendet hos NSObject
. Det betyder att den nya bok
klassen får lite funktionalitet gratis.
Klick Nästa att fortsätta och berätta för Xcode där du vill spara den nya klassen. Se till att spara den nya klassen någonstans i ditt Xcode-projekt.
Xcode har lagt till två nya filer till projektet, Book.h och Book.m. Book.h är huvudfilen till bok
klass och exponerar klassgränssnittet som vi såg tidigare. Ett klassgränssnitt innehåller klassens egenskaper och metoder, och det anger också klassens superklass. Book.m är klassens implementeringsfil och definierar sitt beteende genom att implementera de metoder som deklarerats i klasshuvudfilen.
Öppna Book.h och utforska innehållet. Bortsett från några kommentarer högst upp, innehåller huvudfilen bara tre streckkod. Den första raden importerar stiftelsens ramhistorik. Detta säkerställer att bok
klassen har tillgång till de klasser och protokoll som deklareras i stiftelsens ramverk.
#importera
Den andra och tredje raden utgör ett par. I Mål-C börjar varje klassgränssnitt med @gränssnitt
och slutar med @slutet
, vilka är både kompilatordirektiv, det vill säga kommandon eller instruktioner för kompilatorn. De @gränssnitt
Direktivet följs av klassens namn, ett kolon och klassens superklass-om tillämpligt. Som vi såg tidigare är förälderklassen eller superklassen den klass som den ärver för attribut och beteende.
@interface bok: NSObject @end
NSObject
är roten klass av majoriteten av mål-C klasser. De första två bokstäverna, NS, hänvisa till dess ursprung, NeXTSTEP, som vi såg tidigare i den här artikeln. Genom att ärva från NSObject
, klasser beter sig som mål-C-klasser och ärver ett grundläggande gränssnitt till runtime-systemet.
Innan vi gör ändringar i bok
klass, låt oss ta en snabb topp på Book.m, klassens implementeringsfil. I stället för att importera Foundation Framework, importerar implementeringsfilen huvudrubriken till bok
klass. Varför är det nödvändigt? Implementeringsfilen behöver veta vilka egenskaper och metoder som deklareras i huvudfilen innan den kan implementera beteendet (dvs metoder) i klassen. Importförklaringen följs av klassens genomförande, angiven av @genomförande
och @slutet
.
De bok
klassen är inte särskilt användbar i sin nuvarande genomförande. Gå över till huvudfilen och lägg till tre egenskaper år
, titel
, och författare
, och lägg till en metod som heter bookInfo
.
Egenskaper förklaras med @fast egendom
sökord och kan deklareras var som helst i klassens @gränssnitt
blockera. De @fast egendom
sökord följs av typ och namn på fastigheten. Glöm inte asterisken framför titel
och författare
egenskaper, eftersom ett kakaoobjekt alltid refereras som en pekare.
#importera@interface Bok: NSObject @property int år; @property NSString * titel; @property NSString * författare; - (NSString *) bookInfo; @slutet
Metoddeklarationen liknar en funktionell prototyp, men det finns ett antal viktiga skillnader. Metoddeklarationen börjar med ett minustecken som anger att detta är en förekomstmetod. Klassmetoder är prefixade med ett plustecken. Minustecknet följs av returtypen av metoden mellan parentes, en förekomst av NSString
, och namnet på metoden. Metoddeklarationen slutar med en semikolon.
Jag är säker på att du undrar vad NSString
är och varför det behöver refereras som en pekare. De NSString
klassen är medlem i stiftelsens ramverk. Den förklarar gränssnittet för ett objekt som hanterar en oföränderlig sträng. I den föregående artikeln såg vi att en sträng i C kan representeras av en rad tecken och det är exakt vad NSString
klassen hanterar den en rad tecken under huven. Fördelen med att använda NSString
är att det gör det mycket lättare att arbeta med strängar.
bookInfo
Nu när vi har förklarat bookInfo
metod i klassens huvudfil, är det dags att implementera det i klassens implementeringsfil. Öppna Book.m och lägg till följande kodstämpel någonstans i @genomförande
blockera. Innan vi bryter genomförandet av bookInfo
ner, vi behöver först tala om objektmeddelanden.
- (NSString *) bookInfo NSString * bookInfo = [NSString stringWithFormat: @ "% @ skrivs av% @ och publiceras i% i" self.title, self.author, self.year]; returnera bookInfo;
Vi vet redan att beteendet hos en klass definieras genom dess metoder. För att anropa en metod på ett objekt skickas ett meddelande till objektet. Kontrollera följande kodsats för att förstå detta koncept. Låt oss bryta ner det på rad. I första raden deklarerar vi en ny sträng och tilldelar den en konstant sträng genom att sätta in strängen i dubbla citat och föregå det med en @
skylt.
NSString * string = @ "Detta är en rad tecken."; int längd = [stränglängd]; NSLog (@ "Strängens längd är% i. \ N" längd);
I den andra raden skickar vi ett meddelande om längd
till stränginstansen. Med andra ord kallar vi metoden längd
på stränginstans och metoden returnerar ett heltal. Heltalet är tilldelat till längd
variabel av typ int
. I den sista raden loggar vi längdvariabeln till konsolen genom att ringa NSLog
funktion som vi såg i föregående artikel.
Att skicka meddelanden till objekt är något du kommer att göra mycket, så det är viktigt att du förstår syntaxen. Även om syntaxen är konstig om du är ny i mål-C, är det inte så svårt att förstå. Mellan ruta parentes är objektet till vänster och meddelandet eller metodnamnet till höger.
[objektmeddelande];
Metoder som accepterar argument ser lite annorlunda ut, men den allmänna syntaxen är identisk. De NSString
klassen har till exempel en annan metod som heter substringFromIndex:
. Kolon i slutet av namnet indikerar att denna metod accepterar ett argument. Ringa denna metod på en sträng ser ut så här:
NSString * substring = [sträng substringFromIndex: 5];
Mål-C är känt för sina långa och verbala metodnamn. Ta en titt på följande exempel, som innehåller ett metodnamn med flera argument. Du måste erkänna att namnet på metoden tydligt anger vad metoden gör. Metodnamnet är uppdelad i bitar med varje bit som accepterar ett argument. Objektmeddelanden kommer verkligen att sjunka i när vi börjar arbeta med iOS SDK.
NSString * anotherString = [strängsträngByPaddingToLength: 5 withString: @ "some string" startingAtIndex: 2];
Innan vi går vidare måste vi se över genomförandet av bookInfo
. Metodimplementeringen börjar genom att upprepa metoddeklarationen. Den bakre halvkolonnen ersätts med ett par krökta hängslen, som omsluter metodens genomförande. Vi förklara först en ny sträng, bookInfo
, och tilldela den en ny sträng, skapad med attributen till vår boksinstans (titel
, författare
, och år
). I slutet av bookInfo
metod returnerar vi den nya strängen, bookInfo
, för det är vad metoden förväntar sig, en sträng som returtyp.
Tre saker kräver viss förtydligande. Först, metoden stringWithFormat:
är en klassmetod och inte en förekomstmetod. Vi vet detta eftersom metoden kallas själva klassen, NSString
, inte i en förekomst av klassen. Klassmetoder är vanliga i objektorienterade programmeringsspråk. För det andra representeras formatet specifier för ett objekt av @
symbol (föregås av procenttecknet). Både titel
och författare
är objektsträngar att vara exakta. För det tredje själv
sökord hänvisar alltid till klassens instans. I detta fall, själv
hänvisar till bok
Exempel på vilken metod bookInfo
tillhör.
Om du har arbetat med andra objektorienterade språk kan åtkomstvariabler i Objective-C vara förvirrande. Vi har inte direkt tillgång till en instansvariabel när vi skriver self.title
. Det här är inget mer än en genväg för [egen titel]
. Det senare betyder att vi använder getter-metoden för att fråga förekomsten av instansvariabeln som heter titel
. Detsamma gäller för att ange en instansvariabel. Ta en titt på följande kodbit. Som du kan se, användningen av self.title
är inget mer än syntaktiskt socker.
// Denna uppgift ... self.title = @ "The Hobbit"; // ... motsvarar ... [self setTitle: @ "The Hobbit"];
id
, noll
, och NULL
id
Innan vi börjar använda bok
klass, jag vill prata om några nyckelord som förvirrar människor från tid till annan. När du vill lagra ett objekt utan att uttryckligen definiera typen av objektet använder du id
datatyp, som också är standardtyp för retur- och argumentdeklarationer för mål-C-metoder.
Kraften och användbarheten av id
Datatypen går dock mycket längre. De id
datatyp är en nyckelkomponent i Objective-C: s dynamiska typing och dynamisk bindning. Det är viktigt att förstå att id
Datatypen innehåller ingen information om objektet själv än att det är ett objekt.
I mål-C vet varje objekt vilken klass den tillhör (genom en är en
variabel) och detta är kritiskt. Varför är det så? En av styrkan hos Objective-C är dess dynamiska typning, vilket innebär att typkontroll görs vid körning istället för kompileringstid.
Men sedan id
Datatypen berättar inte kompilatorn någonting om klassen objektet tillhör, objektet själv behöver tillhandahålla denna information till kompilatorn.
Tänk på att det är helt acceptabelt att statiskt skriva ett objekt i Objective-C genom att explicit ange ett objekts klass istället för att använda id
data typ.
Detta ger oss en annan viktig del av Objective-C runtime, dynamisk bindning. I mål-C är en viktig skillnad mellan funktioner och meddelanden att ett meddelande och det mottagande objektet inte går ihop tills runtime.
Vad betyder detta och varför är detta viktigt? Detta innebär att metoden som åberopas som svar på ett meddelande som skickas till ett objekt bestäms vid körning när både meddelandet och objektet är kända. Detta är vad som kallas dynamisk bindning.
noll
och NULL
I mål-C, nyckelordet noll
definieras som a null
objekt, det vill säga en id
med ett värde av 0
. Under huven är det ingen skillnad mellan noll
, Noll
, och NULL
, och det är möjligt att skicka meddelanden till var och en av dem utan att ett undantag kastas.
Konventionen är att använda noll
för objekt, Noll
för klasser och NULL
annat. Att kunna skicka meddelanden till noll
, Noll
, och NULL
har fördelar men det har också nackdelar. För mer information om noll
, Noll
, och NULL
, ta en titt på den här frågan om Stack Overflow.
Öppna main.m och lägg till ett importdeklaration för att importera huvudfilen till bok
klass. Istället för att använda vinkelparentes använder vi dubbla citat för att importera huvudfilen till bok
klass. Dubbel citat används för lokala filer, medan vinklar används för globala inkluderar, med hjälp av projektets sökväg.
#importera#import "Book.h"
Omedelbart under NSLog
ring, lägg till följande kod för att skapa en instans av bok
klass.
Bok * book1 = [[Book alloc] init]; book1.title = @ "The Hobbit"; book1.author = @ "JRR Tolkien"; book1.year = 1937;
I den första raden förklarar vi en variabel av typen bok
och initiera den. Detta är ett bra exempel för att illustrera kapslade metodsamtal. Den första metoden kallade på bok
klassen är alloc
. Detaljerna i detta samtal är inte viktiga. Kärnan är att minnet är allocför det nya objektet och objektet skapas.
På grund av att samtalet näts, i det
Metoden kallas på det nya objektet som skapades av alloc
metod. De i det
metod i detializes det nya objektet, ställer in objektet och gör det klart för användning. De i det
Metoden returnerar förekomsten och, i vårt exempel, tilldelar den till book1
variabel.
De tre följande raderna borde vara bekanta nu, vi ställer in titeln, författaren och publiceringsåret för den nya boken.
Låt oss skapa en annan bok och lägga till båda böckerna i en objektiv-C-grupp. Skapandet av den andra boken är inte ny. Den enda skillnaden är att vi har gjort uttrycklig användning av klassens setters för att ställa in instansvariablerna för den nya instansen.
Boka * book2 = [[Book alloc] init]; [book2 setTitle: @ "Fellowship of the Ring"]; [book2 setAuthor: @ "JRR Tolkien"]; [book2 setYear: 1954]; NSArray * böcker = [[NSArray tilldela] initWithObjects: book1, book2, nil];
I den sista raden skapar vi en instans av NSArray
, en annan klass av stiftelsens ramverk. De NSArray
klassen är en matris som kan lagra en ordnad lista över objekt. Precis som vi gjorde med boken instanser fördelar vi minne och initierar den nya arrayen.
I stället för att ringa i det
, vi ringer dock initWithObjects:
. initWithObjects:
är en utsettsinitierare, vilket innebär att det är en i det
Metod med några extra klockor och visselpipor för att underlätta objektinitiering.
initWithObjects:
accepterar ett antal objekt som du vill lagra i matrisen. Listan över objekt ska alltid sluta med noll
.
Jag har redan nämnt flera gånger att Objective-C är en strikt superset av C och att vi fritt kan kombinera C och Objective-C. Låt oss se hur det här fungerar. Vi börjar med att använda en enkel om annat
uttalande för att kontrollera om arrayen innehåller några objekt. Genom att skicka array ett meddelande om räkna
, det kommer att returnera antalet objekt som den innehåller.
Om arrayen innehåller objekt använder vi en för
loop för att iterera över objekten i arrayen. Under varje iteration frågar vi arrayen för objektet i indexet jag
och skicka objektet - en förekomst av bok
klass-ett meddelande av bookInfo
. Som vi såg tidigare, bookInfo
returnerar en instans av NSString
, som vi loggar in i konsolen.
om ([böckerräkning]> 0) för (int i = 0; i < [books count]; i++) Book *aBook = [books objectAtIndex:i]; NSLog(@"%@", [aBook bookInfo]);
Jag är säker på att du är lite överväldigad av Objective-C. Det här är normalt. Även om Objective-C är inget annat än ett tunt lager ovanpå C-språket, är det ganska mycket på gång.
Medan det finns mer till Objective-C än diskuteras i den här artikeln, vet du nu grunderna och är redo att börja arbeta med iOS SDK. I nästa artikel kommer vi att titta på iOS SDK och utforska dess olika komponenter.