Med det grunnleggende om C som er fortsatt friskt i minnet, er det på tide å bli kjent med Objective-C. Hovedforskjellen med C er at Objective-C er et objektorientert programmeringsspråk, mens C er et prosesseringsprogrammeringsspråk. Dette betyr at vi først må forstå objekter og hvordan de relaterer seg til klasser. Andre viktige begreper som vi vil utforske i denne artikkelen er objektmeldinger, innkapsling og arv.
Mål-C og Kakao er to sentrale komponenter i IOS-plattformen. Til tross for at iOS-plattformen fortsatt er relativt ung, ble Objective-C opprettet tidlig på 1980-tallet på StepStone av Brad Cox og Tom Love. Språket ble opprettet i et forsøk på å kombinere det robuste og smidige C-programmeringsspråket med det elegante Smalltalk-språket. Objektiv-C er en streng supersett av C og, i motsetning til C, er det et høyt programmeringsspråk. Hovedforskjellen mellom C og Objective-C er at sistnevnte er et objektorientert programmeringsspråk, mens C er et prosesseringsprogrammeringsspråk.
Hvordan endte iOS med et språk som ble utviklet på 1980-tallet? Kort etter at NeXT ble grunnlagt av Steve Jobs, lisensierte den Objective-C fra StepStone. NeXT opprettet NeXTSTEP, et verktøy for brukergrensesnitt for NeXT-operativsystemet utviklet i Objective-C. Selv om NeXTSTEP ga et revolusjonerende sett med verktøy, oppnådde NeXT operativsystemet bare lite trekkraft i markedet. I 1996 kjøpte Apple NeXT og NeXTSTEP ble kakao. Sistnevnte gikk vanlig med introduksjonen av OS X i mars 2001 og senere med utgivelsen av iPhone og iOS operativsystemet.
I prosessprogrammering består et program av en serie prosedyrer eller rutiner som utføres for å nå en bestemt stat. I objektorientert programmering, imidlertid, en samling gjenstander samhandler og samarbeider for å fullføre en oppgave. Selv om sluttresultatet kan være identisk, er metodikken og underliggende paradigmer vesentlig forskjellige. Modularitet og kodegenbruk er to av de viktigste fordelene ved objektorienterte programmeringsspråk som vi snart vil se.
Utviklere som er nye til iOS og OS X-økosystemene, blir ofte forvirret av forholdet mellom Objective-C, Cocoa (OS X) og Cocoa Touch (iOS). Hva er Cocoa Touch, og hvordan er det relatert til Objective-C? Kakao er Apples opprinnelige applikasjonsprogrammeringsgrensesnitt (API) for iOS- og OS X-plattformene. Mål-C er språket som driver kakao. Mens denne artikkelen primært fokuserer på Objective-C programmeringsspråket, vil vi se nærmere på Cocoa og Cocoa Touch API senere i denne serien.
En annen hindring for utviklere som er nye til objektorientert programmering, er forskjellen mellom klasser, objekter og forekomster. En klasse er et kast eller en blåkopi for å skape objekter, mens forekomster er unike hendelser i en klasse. Et objekt er en datastruktur som har en tilstand og oppførsel. Til tross for den subtile forskjellen mellom objekter og forekomster, brukes begge termer ofte utveksling.
La oss ta en titt på et eksempel: brødristere. Før en brødrister er produsert, lager ingeniører en blåkopi, som tilsvarer en klasse. Hver brødrister opprettet fra tegningen er en forekomst eller en unik forekomst av klassen. Selv om hver brødrister er laget av samme tegning (klasse), har de hver sin egen stat (farge, antall spor osv.) Og atferd.
Tilstanden til en forekomst er lagret i og definert av dens instansvariabler, eller objektets attributter hvis du vil. Dette bringer oss til et annet sentralt mønster av objektorientert programmering: innkapsling. Innkapsling betyr at den indre representasjonen av et objekt er privat og kun kjent for selve objektet. Dette kan virke som en alvorlig begrensning ved første øyekast. Resultatet er imidlertid modulær og løst koblet kode.
La oss illustrere innkapsling med et annet eksempel. Bilens hastighet måles av bilens internals, men føreren kjenner bilens hastighet ved å se på hastighetsmåleren. Føreren trenger ikke å vite om eller forstå bilens internals for å kjenne bilens hastighet. På samme måte trenger bilens sjåfører ikke å forstå hvordan motorer jobber for å kunne kjøre bilen. Detaljer om hvordan en bil fungerer er skjult fra føreren. Bilens tilstand og oppførsel er skjult fra føreren og er tilgjengelig gjennom bilens grensesnitt (ratt, bremsepedal, dashbord, etc.).
Et annet kraftig paradigme med objektorientert programmering er klasse arv. Når klasse A er a underklasse av klasse B, arver A klasse attributter og oppførsel av klasse B. Klasse B sies å være foreldreklasse eller overklasse i klasse A. Arvelighet fremmer også kodeåtergjengelighet og modularitet.
Metoder er underrutiner knyttet til en klasse, og de definerer oppførselen til en klasse og dens forekomster. Metoden til en klasse har tilgang til internals av en forekomst og kan dermed endre tilstanden til forekomsten. Med andre ord, tilstanden til en forekomst (dvs. instansvariabler) styres av metodene til en forekomst (dvs. forekomst metoder).
På grunn av innkapslingsmønsteret kan ikke instansvariablene av en klasseeksempel åpnes fritt. I stedet blir de tilgjengelige gjennom getters og settere, metoder med det ene formål å få og sette instansvariabler. Egenskaper er en funksjon av Objective-C som gjør etableringen av accessors (getters og setters) trivial. Til tross for brukernes tilgang er det raskt vanskelig å skrive tilgangsmetoder for hver instansvariabel. Vi vil utforske eiendommer mer detaljert senere i denne artikkelen. For nå vurdere egenskaper som wrappers rundt instansvariabler som gjør det lettere å jobbe med forekomstvariabler gjennom getters og setters.
La oss sette vår kunnskap i praksis ved å lage et nytt Xcode-prosjekt for å jobbe med. Opprett et nytt prosjekt i Xcode ved å velge Nytt> Prosjekt ... fra Fil Meny.
Som vi gjorde i forrige artikkel, velg Kommandolinjeverktøy prosjektmal i applikasjon kategori under OS X seksjon.
Sett Produktnavn til bøker og gi prosjektet et organisasjonsnavn og bedriftsidentifikator. For dette prosjektet er det viktig å sette prosjekttypen til Fundament. Årsaken til dette valget vil bli klart senere i denne artikkelen.
Fortell Xcode hvor du vil lagre prosjektet og klikk på Skape knapp. Du kan legge merke til at prosjektet ser annerledes ut enn prosjektet vi opprettet for å lære C. La oss ta et øyeblikk for å se hva forskjellene er.
Prosjektet inneholder noen flere filer og mapper enn kommandolinjeverktøyet vi opprettet i forrige artikkel. I tillegg til main.m og Books.1, Det er to nye mapper, Støtter filer og rammer, hver inneholder ett element.
Støtter filer inneholder en fil som heter Bøker-Prefix.pch. De .PCH filtypen forteller oss at dette er en forkompilert headerfil. Dens formål vil bli klart senere i denne serien.
De rammer mappen inneholder rammene som prosjektet er koblet til. Hva er et rammeverk? Et rammeverk er et bunt eller katalog som inneholder et bibliotek, inkludert dets ressurser, for eksempel bilder og headerfiler. Konseptet med en headerfil vil bli klart på bare et minutt. De rammer mappen inneholder for øyeblikket ett element, Foundation.framework.
Mens du oppretter prosjektet, setter du prosjekttypen til Fundament, noe som betyr at prosjektet er knyttet til stiftelsens rammeverk. Stiftelsens rammeverk er et grunnleggende sett med mål-C-klasser. Senere i denne serien vil vi se nærmere på stiftelsens rammeverk.
Det er på tide å lage din første klasse. Når du oppretter en ny fil (Fil> Ny> Fil ... ), presenteres du med en liste over filmaler. Velge kakao fra OS X delen og velg Mål-C klasse mal for å opprette en ny Objective-C klasse. Klikk neste å fortsette.
Gi den nye klassen et navn på Bok
og sett sin underklasse til NSObject
. Som vi så tidligere, ved å gjøre den nye klassen en underklasse av NSObject
, den nye klassen vil arve attributter og oppførsel av NSObject
. Dette betyr at den nye Bok
klassen får litt funksjonalitet gratis.
Klikk neste å fortsette og fortelle Xcode hvor du vil lagre den nye klassen. Pass på å lagre den nye klassen et sted i ditt Xcode-prosjekt.
Xcode har lagt til to nye filer til prosjektet, Book.h og Book.m. Book.h er headerfilen til Bok
klasse og avslører klassegrensesnittet som vi så tidligere. Et klassegrensesnitt inneholder klassens egenskaper og metoder, og det spesifiserer også klassens superklasse. Book.m er implementeringsfilen til klassen og definerer dens oppførsel ved å implementere metodene som er deklarert i klassens headerfil.
Åpen Book.h og utforske innholdet. Bortsett fra noen kommentarer øverst inneholder headerfilen bare tre linjer med kode. Den første linjen importerer headerfilen til stiftelsens rammeverk. Dette sikrer at Bok
klassen har tilgang til klassene og protokollene deklarert i stiftelsens rammeverk.
#importere
Den andre og tredje linjen danner et par. I Mål-C begynner hvert klassegrensesnitt med @interface
og slutter med @slutt
, som er begge kompilatordirektiver, det vil si kommandoer eller instruksjoner for kompilatoren. De @interface
Direktivet etterfølges av navnet på klassen, et kolon og klassen super-hvis aktuelt. Som vi så tidligere, er foreldreklassen eller superklassen klassen som den arver attributter og atferd.
@interface bok: NSObject @end
NSObject
er rotklassen i flertallet av mål-C-klassene. De to første bokstavene, NS, referer til sin opprinnelse, NeXTSTEP, som vi så tidligere i denne artikkelen. Ved å arve fra NSObject
, klasser oppfører seg som mål-C-klasser og arver et grunnleggende grensesnitt til runtime-systemet.
Før vi gjør endringer i Bok
klasse, la oss ta en rask topp på Book.m, klassens implementeringsfil. I stedet for å importere grunnlagsrammen importerer implementasjonsfilen headerfilen til Bok
klasse. Hvorfor er dette nødvendig? Implementeringsfilen må vite hvilke egenskaper og metoder som er deklarert i headerfilen før den kan implementere atferden (dvs. metoder) i klassen. Importoppgaven etterfølges av gjennomføringen av klassen, angitt av @gjennomføring
og @slutt
.
De Bok
klassen er ikke veldig nyttig i sin nåværende gjennomføring. Gå over til headerfilen og legg til tre egenskaper år
, tittel
, og forfatter
, og legg til en metode som heter bookInfo
.
Egenskaper er deklarert med @eiendom
søkeord og kan deklareres hvor som helst i klassen @interface
blokkere. De @eiendom
Søkeordet etterfølges av typen og navnet på eiendommen. Ikke glem stjernen foran tittel
og forfatter
egenskaper, fordi et kakaoobjekt alltid refereres til som en peker.
#importere@interface Book: NSObject @property int år; @property NSString * tittel; @property NSString * forfatter; - (NSString *) bookInfo; @slutt
Metodeangivelsen ligner litt på en funksjonsprototype, men det er en rekke nøkkelforskjeller. Metodeangivelsen starter med et minustegn som indikerer at dette er en instansmetode. Klassemetoder er prefiks med et plustegn. Minustegnet følger etter returmetoden mellom metoden mellom parentes, en forekomst av NSString
, og navnet på metoden. Metodeangivelsen slutter med en semikolon.
Jeg er sikker på at du lurer på hva NSString
er og hvorfor det må refereres som en peker. De NSString
klassen er medlem av stiftelsens rammeverk. Den erklærer grensesnittet for et objekt som styrer en uforanderlig streng. I forrige artikkel så vi at en streng i C kan representeres av en rekke tegn og det er akkurat det som NSString
klassen klarer det en rekke tegn under hetten. Fordelen med å bruke NSString
er at det gjør det lettere å jobbe med strenge.
bookInfo
Nå som vi har erklært bookInfo
metode i klassens headerfil, er det på tide å implementere det i klassens implementeringsfil. Åpen Book.m og legg til følgende kodestykke et sted i @gjennomføring
blokkere. Før vi bryter gjennom implementeringen av bookInfo
ned, vi må først snakke om objektmeldinger.
- (NSString *) bookInfo NSString * bookInfo = [NSString stringWithFormat: @ "% @ ble skrevet av% @ og publisert i% i" self.title, self.author, self.year]; returnere bookInfo;
Vi vet allerede at oppførselen til en klasse er definert gjennom sine metoder. For å ringe en metode på et objekt, sendes en melding til objektet. Kontroller følgende kodestykke for å forstå dette konseptet. La oss bryte det ned linje for linje. I den første linjen erklærer vi en ny streng og tilordner den en konstant streng ved å pakke strengen i dobbelt anførselstegn og forutse den med en @
skilt.
NSString * string = @ "Dette er en streng med tegn."; int lengde = [strenglengde]; NSLog (@ "Lengden på strengen er% i. \ N" lengde);
I den andre linjen sender vi en melding om lengde
til strengeksemplet. Med andre ord kaller vi metoden lengde
på strengeninstansen og metoden returnerer et heltall. Heltallet er tildelt til lengde
variabel av type int
. I den siste linjen logger vi lengdevariabelen til konsollen ved å ringe NSLog
fungere som vi så i forrige artikkel.
Å sende meldinger til objekter er noe du vil gjøre mye, så det er viktig å forstå syntaksen. Selv om syntaksen ser merkelig ut hvis du er ny i Objective-C, er det ikke så vanskelig å forstå. Mellom firkantede parenteser er objektet til venstre og meldings- eller metodenavnet til høyre.
[objektmelding];
Metoder som aksepterer argumenter, ser litt annerledes ut, men den generelle syntaksen er identisk. De NSString
klasse, for eksempel, har en annen metode som heter substringFromIndex:
. Tykktarmen på slutten av navnet indikerer at denne metoden godtar et argument. Kaller denne metoden på en streng ser slik ut:
NSString * substring = [streng substringFromIndex: 5];
Mål-C er kjent for sine lange og verbose metodenavn. Ta en titt på følgende eksempel, som inneholder et metodenavn med flere argumenter. Du må innrømme at navnet på metoden tydelig sier hva metoden gjør. Metodenavnet er delt inn i biter med hver bit, og aksepterer et argument. Objektmeldinger vil virkelig synke inn når vi begynner å jobbe med iOS SDK.
NSString * anotherString = [strengstrengByPaddingToLength: 5 withString: @ "some string" startingAtIndex: 2];
Før vi går videre, må vi se gjennom implementeringen av bookInfo
. Metodimplementeringen starter ved å gjenta metodedeklarasjonen. Den bakre semicolon er erstattet med et par krøllete braces, som vikle rundt implementeringen av metoden. Vi erklærer først en ny streng, bookInfo
, og tilordne den en ny streng, opprettet med attributter av vår bokinstans (tittel
, forfatter
, og år
). På slutten av bookInfo
metode, vi returnerer den nye strengen, bookInfo
, fordi det er hva metoden forventer, en streng som returtype.
Tre ting krever noe avklaring. Først måten stringWithFormat:
er en klassemetode og ikke en instansmetode. Vi vet dette fordi metoden kalles på selve klassen, NSString
, ikke på en forekomst av klassen. Klassemetoder er vanlige i objektorienterte programmeringsspråk. For det andre er formatet spesifiserer for et objekt representert av @
symbol (foran med prosent-tegn). Både tittel
og forfatter
er objekter-strenger å være presise. Tredje, den selv-
Søkeord refererer alltid til klassens forekomst. I dette tilfellet, selv-
refererer til Bok
eksempel som metoden bookInfo
tilhører.
Hvis du har jobbet med andre objektorienterte språk, kan tilgangsvariabler i Objective-C være forvirrende. Vi har ikke direkte tilgang til en instansvariabel når vi skriver self.title
. Dette er ikke noe mer enn en snarvei for [selv tittel]
. Sistnevnte betyr at vi bruker gettermetoden til å spørre forekomsten for instansvariabelen som heter tittel
. Det samme gjelder for å sette en instansvariabel. Ta en titt på følgende kodestykke. Som du kan se, bruk av self.title
er ikke noe mer enn syntaktisk sukker.
// Denne oppdraget ... self.title = @ "The Hobbit"; // ... tilsvarer ... [self setTitle: @ "The Hobbit"];
id
, nil
, og NULL
id
Før vi begynner å bruke Bok
klasse, jeg vil snakke om noen få søkeord som forvirrer folk fra tid til annen. Når du vil lagre et objekt uten å eksplisitt definere typen av objektet, bruker du id
datatype, som også er standardtypen for retur- og argumentdeklarasjoner for mål-C-metoder.
Kraften og nytte av id
datatypen går mye lenger, skjønt. De id
Datatype er en nøkkelkomponent i Objective-Cs dynamiske skriving og dynamisk binding. Det er viktig å forstå at id
Datatypen inneholder ingen informasjon om selve objektet, bortsett fra at det er et objekt.
I Objective-C vet hvert objekt hvilken klasse den tilhører (gjennom en er en
variabel) og dette er kritisk. Hvorfor det? En av styrkene til Objective-C er dens dynamiske skriving, noe som betyr at typekontroll utføres ved kjøring i stedet for kompileringstid.
Men siden id
datatypen forteller ikke kompilatoren noe om klassen objektet tilhører, objektet selv trenger å gi denne informasjonen til kompilatoren.
Husk at det er helt akseptabelt å statisk skrive et objekt i Objective-C ved å spesifisere spesifikt en objekts klasse i stedet for å bruke id
data-type.
Dette bringer oss til en annen viktig del av Objective-C runtime, dynamisk binding. I Mål-C er en viktig forskjell mellom funksjoner og meldinger at en melding og mottaksobjektet ikke er sammenføyet til kjøretid.
Hva betyr dette og hvorfor er dette viktig? Dette betyr at metoden som påberopes som svar på en melding som sendes til en gjenstand, bestemmes ved kjøretid når både meldingen og objektet er kjent. Dette er det som kalles dynamisk binding.
nil
og NULL
I Mål-C, søkeordet nil
er definert som a null
objekt, det vil si en id
med en verdi på 0
. Under hetten er det ingen forskjell mellom nil
, Nil
, og NULL
, og det er mulig å sende meldinger til hver av dem uten at et unntak kastes.
Konvensjonen er å bruke nil
for gjenstander, Nil
for klasser og NULL
ellers. Å kunne sende meldinger til nil
, Nil
, og NULL
har fordeler, men det har også ulemper. For mer informasjon om nil
, Nil
, og NULL
, ta en titt på dette spørsmålet om Stack Overflow.
Åpen main.m og legg til en importoppgave for å importere headerfilen til Bok
klasse. I stedet for å bruke vinkelbeslag, bruker vi doble anførselstegn for å importere headerfilen til Bok
klasse. Doble anførselstegn brukes for lokale filer, mens vinkelbeslag brukes til global inkluderer, ved hjelp av prosjektets innfelt sti.
#importere#import "Book.h"
Umiddelbart under NSLog
ring, legg til følgende utdrag for å opprette en forekomst av Bok
klasse.
Book * book1 = [[Book alloc] init]; book1.title = @ "The Hobbit"; book1.author = @ "JRR Tolkien"; book1.year = 1937;
I den første linjen erklærer vi en variabel av typen Bok
og initialiser den. Dette er et godt eksempel for å illustrere nestede metallsamtaler. Den første metoden ringte på Bok
klassen er Alloc
. Detaljer om denne anropet er ikke viktige. Gjerningen er at minnet er Allocated for det nye objektet og objektet er opprettet.
På grunn av nesting av samtalene, den i det
Metoden kalles på det nye objektet som ble opprettet av Alloc
metode. De i det
metode i detIaliserer det nye objektet, setter opp objektet og gjør det klart for bruk. De i det
Metoden returnerer forekomsten og, i vårt eksempel, tilordner den til book1
variabel.
De neste tre linjene skal være kjent nå, vi setter tittelen, forfatteren og utgivelsesåret til den nye boken.
La oss lage en annen bok og legge begge bøkene til et mål-C-array. Opprettelsen av den andre boken er ikke ny. Den eneste forskjellen er at vi har gjort uttrykkelig bruk av klassens settere for å angi instansvariablene for den nye forekomsten.
Book * book2 = [[Book alloc] init]; [book2 setTitle: @ "The Community of the Ring"]; [book2 setAuthor: @ "JRR Tolkien"]; [book2 setYear: 1954]; NSArray * bøker = [[NSArray alloc] initWithObjects: book1, book2, null];
I den siste linjen oppretter vi en forekomst av NSArray
, en annen klasse av stiftelsens rammeverk. De NSArray
klassen er en matrise som kan lagre en bestilt liste over objekter. Akkurat som vi gjorde med boksinstansene, allokerer vi minne og initialiserer den nye gruppen.
I stedet for å ringe i det
, men vi kaller initWithObjects:
. initWithObjects:
er en utpekt initialiserer, som betyr at det er en i det
Metode med noen ekstra klokker og fløyter for å lette objektinitialisering.
initWithObjects:
aksepterer et antall objekter du ønsker å lagre i matrisen. Listen over objekter bør alltid ende med nil
.
Jeg har allerede nevnt flere ganger at Objective-C er et strengt supersett av C, og at vi fritt kan kombinere C og Objective-C. La oss se hvordan dette virker. Vi starter med å bruke en enkel hvis / annet
setning for å sjekke om arrayet inneholder objekter. Ved å sende arrayet en melding av telle
, det vil returnere antall gjenstander det inneholder.
Hvis arrayet inneholder objekter, bruker vi en til
loop for å iterere over objektene i arrayet. Under hver iterasjon spør vi arrayet for objektet på indeksen Jeg
og send objektet - en forekomst av Bok
klasse-en melding av bookInfo
. Som vi så tidligere, bookInfo
returnerer en forekomst av NSString
, som vi logger inn på konsollen.
hvis ([bøker teller]> 0) for (int i = 0; i < [books count]; i++) Book *aBook = [books objectAtIndex:i]; NSLog(@"%@", [aBook bookInfo]);
Jeg er sikker på at du er litt overveldet av Objective-C. Dette er normalt. Selv om Objective-C ikke er noe mer enn et tynt lag på toppen av C-språket, går det ganske mye.
Mens det er mer til Objective-C enn diskutert i denne artikkelen, vet du nå det grunnleggende og er klar til å begynne å jobbe med iOS SDK. I neste artikkel vil vi se på iOS SDK og utforske sine ulike komponenter.