Objective-C hämtar sin objektsyntax från Smalltalk. Alla syntaxen för icke-objektorienterade operationer (inklusive primitiva variabler, förbehandling, uttryck, funktionsdeklarationer och funktionsanrop) är identiska med C, medan syntaxen för objektorienterade funktioner är en implementering av Smalltalk-stilmeddelanden.
MessagesEdit
Objective-C-modellen för objektorienterad programmering baseras på meddelande som skickas till objektinstanser. I mål – C kallar man inte en metod; man skickar ett meddelande., Detta är till skillnad från simula-stil programmeringsmodell som används av C++. Skillnaden mellan dessa två begrepp är hur koden som refereras av metoden eller meddelandenamnet exekveras. I ett Simula-stilspråk är metodnamnet i de flesta fall bundet till en sektion av kod i målklassen av kompilatorn. I Smalltalk och Objective-C löses målet för ett meddelande vid körning, med det mottagande objektet som tolkar meddelandet., En metod identifieras av en väljare eller SEL-en unik identifierare för varje meddelandenamn, ofta bara en NUL-terminerad sträng som representerar sitt namn – och löstes till en C-metodpekare som implementerar den: en IMP. En följd av detta är att meddelandepassningssystemet inte har någon typkontroll. Objektet som meddelandet riktas till-mottagaren-är inte garanterat att svara på ett meddelande, och om det inte gör det, väcker det ett undantag.,
att skicka meddelandemetoden till objektet som pekas på av pekaren obj skulle kräva följande kod i c++:
obj->method(argument);
i Objective-C skrivs detta enligt följande:
;
samtalet ”method” översätts av kompilatorn till objc_msgSend(ID self, sel op,…) familj av runtime funktioner. Olika implementeringar hanterar moderna tillägg som super. I GNU-familjer heter den här funktionen objc_msg_sendv, men den har blivit föråldrad till förmån för ett modernt lookup-system under objc_msg_lookup.,
båda programmeringsstilarna har sina styrkor och svagheter. Objektorienterad programmering i Simula (C++) stil tillåter flera arv och snabbare utförande genom att använda kompilering-tid bindning när det är möjligt, men det stöder inte dynamisk bindning som standard. Det tvingar också alla metoder att ha ett motsvarande genomförande om de inte är abstrakta. Den Smalltalk-stil programmering som används i mål – C tillåter meddelanden att gå ogenomförda, med metoden löst till dess genomförande vid körning., Ett meddelande kan till exempel skickas till en samling objekt, som endast vissa förväntas svara på, utan rädsla för att producera runtime-fel. Meddelande som passerar kräver inte heller att ett objekt definieras vid kompileringstid. En implementering krävs fortfarande för att metoden ska anropas i det härledda objektet. (Se avsnittet dynamisk typning nedan för fler fördelar med dynamisk (sen) bindning.)
gränssnitt och implementationsEdit
Objective-C kräver att gränssnittet och genomförandet av en klass är i separat deklarerade kodblock., Genom konvention placerar Utvecklare gränssnittet i en huvudfil och implementeringen i en kodfil. Rubrikfilerna, normalt suffixed .h, liknar C header filer medan genomförandet (metod) filer, normalt suffixed .m, kan vara mycket lik C-kodfiler.
InterfaceEdit
detta är analogt med klassdeklarationer som används i andra objektorienterade språk, såsom C++ eller Python.
gränssnittet för en klass definieras vanligtvis i en huvudfil. En vanlig konvention är att namnge huvudfilen efter namnet på klassen, t.ex. boll.,h skulle innehålla gränssnittet för klassbollen.
en gränssnittsdeklaration har formen:
i ovanstående, plus tecken betecknar klassmetoder, eller metoder som kan anropas på klassen själv (inte på en instans), och minus tecken betecknar instansmetoder, som endast kan anropas på en viss instans av klassen. Klassmetoder har inte heller tillgång till instansvariabler.,
koden ovan motsvarar ungefär följande C++ – gränssnitt:
Observera att instanceMethod2With2Parameters: param2_callName: visar sammanflätningen av väljare segment med argumentuttryck, för vilka det inte finns någon direkt motsvarighet i c / c++.
Returtyper kan vara vilken standard C-typ som helst, en pekare till ett generiskt Objektc-objekt, en pekare till en viss typ av objekt som NSArray*, Nsimage * eller NSString * eller en pekare till den klass som metoden tillhör (instancetype). Standard tillbaka typ är den generiska Objective-C typ id.,
Metodargument börjar med ett namn som markerar argumentet som är en del av metodens namn, följt av ett kolon följt av den förväntade argumenttypen inom parentes och argumentnamnet. Etiketten kan utelämnas.
ett derivat av gränssnittsdefinitionen är kategorin, vilket gör att man kan lägga till metoder i befintliga klasser.
ImplementationEdit
gränssnittet förklarar bara klassgränssnittet och inte metoderna själva: den faktiska koden skrivs i implementeringsfilen., Implementation (metod) filer har normalt filändelsen .m
, som ursprungligen betecknade”meddelanden”.
@implementation classname+ (return_type)classMethod { // implementation}- (return_type)instanceMethod { // implementation}@end
metoder skrivs med sina gränssnittsdeklarationer.Jämföra Objective – C och C:
- (int)method:(int)i { return ;}
int function(int i) { return square_root(i);}
syntaxen tillåter pseudo-namngivning av argument.
interna representationer av en metod varierar mellan olika implementeringar av Objective-C., Om myColor är av klassens färg, instansmetod-changeColorToRed: grön: blå: kan vara internt märkt _i_Color_changeColorToRed_green_blue. I är att hänvisa till en instans metod, med klassen och sedan metod namn bifogade och kolon ändras till understreck. Eftersom parameterordningen är en del av metodens namn kan den inte ändras för att passa kodningsstil eller uttryck som med sanna namngivna parametrar.
men interna namn på funktionen används sällan direkt. I allmänhet konverteras meddelanden till funktionsanrop som definieras i Objective-C runtime library., Det är inte nödvändigtvis känt vid länktid vilken metod som kommer att kallas eftersom mottagarens klass (objektet som skickas meddelandet) inte behöver vara känt förrän runtime.
InstantiationEdit
När en Objective-C-klass är skriven kan den instansieras. Detta görs genom att först allokera en oinitierad instans av klassen (ett objekt) och sedan genom att initiera den. Ett objekt är inte fullt fungerande förrän båda stegen har slutförts., Dessa steg bör utföras med en rad kod så att det aldrig finns ett tilldelat objekt som inte har genomgått initiering (och eftersom det är oklokt att behålla det mellanliggande resultatet eftersom -init
kan returnera ett annat objekt än det som det kallas).,
Instantiering med standardinitieraren för ingen parameter:
MyObject *foo = init];
Instantiering med en anpassad initialiserare:
MyObject *foo = initWithString:myString];
om ingen Anpassad initiering utförs kan den ”nya” metoden ofta användas i stället för allokeringsinit-meddelandena:
MyObject *foo = initWithString:myString];
MyObject *foo = ;
vissa klasser implementerar även initialisatorer för klassmetoden., Som +new
kombinerar de +alloc
och -init
, men till skillnad från +new
returnerar de en autoreleased instans. Vissa klassmetod initialiserare ta parametrar:
MyObject *foo = ;MyObject *bar = ;
allokeringsmeddelandet allokerar tillräckligt med minne för att hålla alla instansvariabler för ett objekt, ställer in alla instansvariabler till nollvärden, och förvandlar minnet till en instans av klassen; vid något tillfälle under initieringen är minnet en instans av superklassen.,
init-meddelandet utför konfigurationen av instansen vid skapandet. Init-metoden skrivs ofta enligt följande:
- (id)init { self = ; if (self) { // perform initialization of object here } return self;}
i ovanstående exempel märker du id
returtyp. Denna typ står för ”pekare till något objekt” i Objective-C (se avsnittet dynamisk typning).
initieringsmönstret används för att försäkra att objektet initieras korrekt av dess superklass innan init-metoden utför initieringen., Det utför följande åtgärder:
- self = skickar superclass-instansen ett init-meddelande och tilldelar resultatet till själv (pekare till det aktuella objektet).
- Om (själv)kontrollerar om den returnerade objektpekaren är giltig innan någon initiering utförs.
- returnera selfReturns värdet av själv till den som ringer.
en icke-giltig objektpekare har värdet noll; villkorliga uttalanden som ”if”behandla noll som en null-pekare, så initieringskoden kommer inte att utföras om returnerade noll., Om det finns ett fel i initieringen bör init-metoden utföra nödvändig rengöring, inklusive att skicka ett” release ” – meddelande till själv och returnera noll för att indikera att initieringen misslyckades. Varje kontroll av sådana fel får endast utföras efter att ha kallat superklassinitiering för att säkerställa att förstöra objektet kommer att göras korrekt.
om en klass har mer än en initieringsmetod måste endast en av dem (den ”utsedda initialiseraren”) följa detta mönster; andra bör anropa den utsedda initialiseraren istället för superklassinitialiseraren.,
ProtocolsEdit
på andra programmeringsspråk kallas dessa ”gränssnitt”.
mål-C utvidgades vid nästa för att införa begreppet multipel arv av specifikation, men inte genomförande, genom införandet av protokoll. Detta är ett mönster som kan uppnås antingen som en abstrakt multipel ärftlig basklass i C++, eller som ett” gränssnitt ” (som i Java och C#). Objective – C använder sig av Ad hoc-protokoll som kallas informella protokoll och kompilatortvingade protokoll som kallas formella protokoll.,
ett informellt protokoll är en lista över metoder som en klass kan välja att implementera. Det anges i dokumentationen, eftersom det inte har någon närvaro på språket. Informella protokoll implementeras som en kategori (se nedan) på NSObject och innehåller ofta valfria metoder, som, om de implementeras, kan ändra beteendet hos en klass. Till exempel kan en textfältklass ha en delegat som implementerar ett informellt protokoll med en valfri metod för att utföra automatisk komplettering av användarskriven text., Textfältet upptäcker om delegaten implementerar den metoden (via reflektion) och i så fall anropar delegatens metod för att stödja funktionen automatisk komplettering.
ett formellt protokoll liknar ett gränssnitt i Java, C# och ada 2005. Det är en lista över metoder som någon klass kan förklara sig att genomföra. Versioner av Objective-C före 2.0 krävde att en klass måste genomföra alla metoder i ett protokoll som den förklarar sig anta; kompilatorn kommer att avge ett fel om klassen inte implementerar varje metod från sina deklarerade protokoll. Mål C 2.,0 Utökat stöd för att markera vissa metoder i ett protokoll frivilligt, och kompilatorn kommer inte att genomdriva genomförandet av valfria metoder.
en klass måste deklareras för att genomföra det protokollet för att det ska överensstämma med det. Detta är detekterbart vid körning. Formella protokoll kan inte ge några implementeringar; de försäkrar helt enkelt callers att klasser som överensstämmer med protokollet kommer att ge implementeringar. I nästa/Apple-bibliotek används protokoll ofta av det distribuerade Objektsystemet för att representera förmågan hos ett objekt som körs på ett fjärrsystem.,
syntaxen
@protocol NSLocking- (void)lock;- (void)unlock;@end
anger att det finns en abstrakt idé om låsning. Genom att ange i klassdefinitionen att protokollet implementeras,
@interface NSLock : NSObject <NSLocking>// ...@end
instanser av NSLock hävdar att de kommer att tillhandahålla en implementering för de två instansmetoderna.
dynamisk typingEdit
Objective-C, som Smalltalk, kan använda dynamisk typning: ett objekt kan skickas ett meddelande som inte anges i dess gränssnitt., Detta kan möjliggöra ökad flexibilitet, eftersom det tillåter ett objekt att ”fånga” ett meddelande och skicka meddelandet till ett annat objekt som kan svara på meddelandet på lämpligt sätt, eller på samma sätt skicka meddelandet till ett annat objekt. Detta beteende kallas vidarebefordran av meddelanden eller delegering (se nedan). Alternativt kan en felhanterare användas om meddelandet inte kan vidarebefordras. Om ett objekt inte vidarebefordrar ett meddelande, svarar på det eller hanterar ett fel, kommer systemet att generera ett runtime-undantag., Om meddelanden skickas till noll (nollobjektpekaren) ignoreras de tyst eller höjer ett generiskt undantag, beroende på kompilatoralternativ.
statisk typningsinformation kan också eventuellt läggas till variabler. Denna information kontrolleras sedan vid sammanställningen. I de följande fyra uttalandena tillhandahålls allt mer specifik typinformation. Uttalandena är likvärdiga vid körning, men den extra informationen gör det möjligt för kompilatorn att varna programmeraren om det godkända argumentet inte matchar den angivna typen.,
- (void)setMyValue:(id)foo;
i ovanstående uttalande kan foo vara av vilken klass som helst.
- (void)setMyValue:(id<NSCopying>)foo;
i ovanstående uttalande kan foo vara en instans av vilken klass som helst som överensstämmer medNSCopying
– protokollet.
- (void)setMyValue:(NSNumber *)foo;
i ovanstående uttalande måste foo vara en instans av NSNumber-klassen.
- (void)setMyValue:(NSNumber<NSCopying> *)foo;
i ovanstående uttalande måste foo vara en instans av NSNumber-klassen, och den måste överensstämma medNSCopying
– protokollet.,
i Objective-C representeras alla objekt som pekare, och statisk initiering är inte tillåten. Det enklaste objektet är den typ som ID (objc_obj *) pekar på, som bara har en ISA-pekare som beskriver sin klass. Andra typer från C, som värden och strukturer, är oförändrade eftersom de inte ingår i objektsystemet. Detta beslut skiljer sig från C++ – objektmodellen, där strukturer och klasser förenas.
ForwardingEdit
Objective-C tillåter att ett meddelande skickas till ett objekt som kanske inte svarar., I stället för att svara eller helt enkelt släppa meddelandet kan ett objekt vidarebefordra meddelandet till ett objekt som kan svara. Vidarebefordran kan användas för att förenkla genomförandet av vissa designmönster, såsom observatörsmönstret eller proxymönstret.
Objective-C runtime anger ett par metoder i Object
ett objekt som vill implementera vidarebefordran behöver bara åsidosätta vidarebefordringsmetoden med en ny metod för att definiera vidarebefordringsbeteendet. Åtgärdsmetoden performv:: behöver inte åsidosättas, eftersom denna metod endast utför en åtgärd baserad på väljaren och argumenten., Lägg märke till SEL
– typen, som är typen av meddelanden i Objective-C.
Obs: i OpenStep, Cocoa och GNUstep använder man inte Objektklassen de vanligaste ramarna för Objective-C. De – (void)forwardInvocation:(NSInvocation *)anInvocation metod för NSObject klass används för att göra vidarebefordran.
ExampleEdit
här är ett exempel på ett program som visar grunderna för vidarebefordran.
skotare.h skotare.m mottagare.h
#import <objc/Object.h>// A simple Recipient object.@interface Recipient : Object- (id)hello;@end
mottagare.m
#import "Recipient.h"@implementation Recipient- (id)hello { printf("Recipient says hello!\n"); return self;}@end
main.,m
NotesEdit
vid kompilering med gcc rapporterar kompilatorn:
kompilatorn rapporterar den punkt som tidigare gjorts, att speditören inte svarar på hello-meddelanden. Under denna omständighet är det säkert att ignorera varningen sedan vidarebefordran genomfördes. Kör programmet producerar denna utgång:
$ ./a.outRecipient says hello!
CategoriesEdit
under utformningen av Objective-C, en av de viktigaste frågorna var underhåll av stora kodbaser., Erfarenheten från den strukturerade programmeringsvärlden hade visat att ett av de viktigaste sätten att förbättra koden var att bryta ner den i mindre bitar. Objective-C lånade och utvidgade begreppet kategorier från Smalltalk implementeringar för att hjälpa till med denna process.
dessutom läggs metoderna inom en kategori till i en klass vid körtid. Således tillåter kategorier programmeraren att lägga till metoder till en befintlig klass – en öppen klass-utan att behöva kompilera om den klassen eller till och med ha tillgång till källkoden., Till exempel, om ett system inte innehåller en stavningskontroll i dess Strängimplementering, kan det läggas till utan att ändra Strängkällkoden.
metoder inom kategorier blir oskiljbara från metoderna i en klass när programmet körs. En kategori har full tillgång till alla instansvariabler inom klassen, inklusive privata variabler.
om en kategori deklarerar en metod med samma metodsignatur som en befintlig metod i en klass, används kategorins metod. Således kan Kategorier inte bara lägga till metoder i en klass utan också ersätta befintliga metoder., Denna funktion kan användas för att åtgärda fel i andra klasser genom att skriva om sina metoder, eller för att orsaka en global förändring av en klass beteende inom ett program. Om två kategorier har metoder med samma namn men olika metodsignaturer, är det odefinierat vilken kategoris metod som antas.
andra språk har försökt lägga till den här funktionen på olika sätt. TOM tog målet-C-systemet ett steg längre och tillåts för tillägg av variabler också. Andra språk har använt prototypbaserade lösningar istället, den mest anmärkningsvärda är själv.
C# och Visual Basic.,NET-språk implementerar ytligt liknande funktionalitet i form av förlängningsmetoder, men dessa saknar tillgång till klassens privata variabler. Ruby och flera andra dynamiska programmeringsspråk hänvisar till tekniken som”monkey patching”.
Logtalk implementerar ett koncept av kategorier (som förstklassiga enheter) som utgår från funktionaliteten för Objective-C-kategorier (Logtalk-kategorier kan också användas som finkorniga enheter av sammansättning när de definierar t. ex. nya klasser eller prototyper; i synnerhet kan en Logtalk-kategori praktiskt taget importeras av valfritt antal klasser och prototyper).,
exempel användning av categoriesEdit
det här exemplet bygger upp en Heltalsklass genom att först definiera en grundläggande klass med endast implementerade accessor-metoder och lägga till två kategorier, aritmetik och Display, som utökar grundklassen. Även om kategorier kan få tillgång till basklassens privata datamedlemmar är det ofta bra att få tillgång till dessa privata datamedlemmar genom accessor-metoderna, vilket hjälper till att hålla kategorierna mer oberoende från basklassen. Att genomföra sådana accessorer är en typisk användning av kategorier. En annan är att använda kategorier för att lägga till metoder i basklassen., Det anses dock inte som god praxis att använda kategorier för underklassöverridning, även känd som apa lapp. Informella protokoll implementeras som en kategori på klassen base NSObject. Genom konvention, filer som innehåller kategorier som utökar basklasser kommer att ta namnet BaseClass+ExtensionClass.H.
heltal.h
#import <objc/Object.h>@interface Integer : Object { int integer;}- (int)integer;- (id)integer:(int)_integer;@end
heltal.m heltal+aritmetik.h
#import "Integer.h"@interface Integer (Arithmetic)- (id) add: (Integer *) addend;- (id) sub: (Integer *) subtrahend;@end
heltal+aritmetik.m Heltal+Display.h
#import "Integer.h"@interface Integer (Display)- (id) showstars;- (id) showint;@end
heltal+Display.m stora.,m
NotesEdit
sammanställning utförs, till exempel av:
gcc -x objective-c main.m Integer.m Integer+Arithmetic.m Integer+Display.m -lobjc
man kan experimentera genom att lämna ut #import ”Integer+aritmetik.h ” och linjer och utelämna heltal+aritmetik.m i Kompilering. Programmet kommer fortfarande att köras. Detta innebär att det är möjligt att blanda och matcha tillsatta kategorier om det behövs; om en kategori inte behöver ha någon förmåga, kan det helt enkelt inte kompilera in.
Posingedit
Objective-C tillåter en klass att helt ersätta en annan klass inom ett program. Den ersättande klassen sägs ”posera som” målklassen.,
klass posering förklarades föråldrad med Mac OS X v10. 5, och är otillgänglig i 64-bitars runtime. Liknande funktionalitet kan uppnås genom att använda metoden swizzling i kategorier, som swappar en metods genomförande med en annan som har samma signatur.
för de versioner som fortfarande stöder posering tas alla meddelanden som skickas till målklassen istället emot av poseringsklassen. Det finns flera begränsningar:
- en klass kan endast utgöra en av dess direkta eller indirekta superklasser.,
- poseringsklassen får inte definiera några nya instansvariabler som saknas i målklassen (även om den kan definiera eller åsidosätta metoder).
- målklassen kanske inte har fått några meddelanden innan poseringen.
poserar, på samma sätt som kategorier, möjliggör global förstärkning av befintliga klasser. Poserar tillåter två funktioner frånvarande från kategorier:
- en poserar klass kan kalla åsidosatta metoder genom super, vilket införlivar genomförandet av målklassen.
- en poseringsklass kan åsidosätta metoder som definieras i kategorier.,
till exempel
detta fångar upp varje anrop av setMainMenu till NSApplication.
#importEdit
på C-språket gör#include
förkompileringsdirektivet alltid att en fils innehåll infogas i källan vid den punkten. Objective – C har #import
– direktivet, motsvarande förutom att varje fil endast inkluderas en gång per sammanställningsenhet, vilket eliminerar behovet av att inkludera vakter.