Objective-C ontleent zijn objectsyntaxis aan Smalltalk. Alle syntaxis voor niet-object-georiënteerde operaties (inclusief primitieve variabelen, pre-processing, expressies, functie declaraties, en functie aanroepen) zijn identiek aan die van C, terwijl de syntaxis voor object-georiënteerde functies is een implementatie van Smalltalk-stijl messaging.
MessagesEdit
Het Objective-C-model van objectgeoriënteerd programmeren is gebaseerd op het doorgeven van berichten aan Object-instanties. In Objective-C roept men geen methode aan; men stuurt een boodschap., Dit is in tegenstelling tot het simula-stijl programmeermodel gebruikt door C++. Het verschil tussen deze twee concepten is in hoe de code waarnaar wordt verwezen door de methode of berichtnaam wordt uitgevoerd. In een Simula – stijl taal is de method naam in de meeste gevallen gebonden aan een sectie code in de doelklasse door de compiler. In Smalltalk en Objective-C wordt het doel van een bericht opgelost tijdens runtime, waarbij het ontvangende object zelf het bericht interpreteert., Een methode wordt geà dentificeerd door een selector of SEL — een unieke identifier voor elke berichtnaam, vaak gewoon een NUL-beëindigde string die zijn naam vertegenwoordigt-en opgelost naar een C methode pointer die het implementeert: een IMP. Een gevolg hiervan is dat het berichtdoorlaatsysteem geen typecontrole heeft. Het object waarop het bericht is gericht — de ontvanger — reageert niet gegarandeerd op een bericht, en als dat niet het geval is, roept het een uitzondering op.,
Het verzenden van de berichtmethode naar het object waarnaar wordt verwezen door de pointer obj vereist de volgende code in c++:
obj->method(argument);
In Objective-C wordt dit als volgt geschreven:
;
De “method” aanroep wordt door de compiler vertaald naar het objc_msgsend(ID self, sel op,…) familie van runtime functies. Verschillende implementaties behandelen moderne toevoegingen zoals super. In GNU-families wordt deze functie objc_msg_sendv genoemd, maar het is afgekeurd ten gunste van een modern lookup-systeem onder objc_msg_lookup.,
beide programmeerstijlen hebben hun sterke en zwakke punten. Objectgeoriënteerd programmeren in de simula (C++) stijl maakt meerdere overerving en snellere uitvoering mogelijk door compilatietijd binding te gebruiken waar mogelijk, maar het ondersteunt standaard geen dynamische binding. Het dwingt ook alle methoden om een overeenkomstige implementatie te hebben, tenzij ze abstract zijn. De Smalltalk-stijl programmering zoals gebruikt in Objective-C laat berichten gaan ongeà mplementeerd, met de methode opgelost om de implementatie ervan tijdens runtime., Bijvoorbeeld, een bericht kan worden verzonden naar een verzameling van objecten, waarop slechts een aantal zal worden verwacht te reageren, zonder angst voor het produceren van runtime fouten. Het doorgeven van berichten vereist ook niet dat een object wordt gedefinieerd tijdens het compileren. Een implementatie is nog steeds nodig om de methode in het afgeleide object aan te roepen. (Zie de sectie dynamisch typen hieronder voor meer voordelen van dynamische (late) binding.)
Interfaces en implementatiededit
Objective-C vereist dat de interface en implementatie van een klasse in afzonderlijk gedeclareerde codeblokken zijn., Volgens afspraak plaatsen ontwikkelaars de interface in een header-bestand en de implementatie in een code-bestand. De header bestanden, normaal achtervoegsel .h, zijn vergelijkbaar met C header bestanden terwijl de implementatie (methode) bestanden, normaal achtervoegsel .m, kan zeer vergelijkbaar zijn met C-code bestanden.
InterfaceEdit
Dit is analoog aan klassenverklaringen zoals gebruikt in andere objectgeoriënteerde talen, zoals C++ of Python.
De interface van een klasse wordt meestal gedefinieerd in een header-bestand. Een gemeenschappelijke conventie is om de header bestand na de naam van de klasse, bijvoorbeeld Ball.,h zou de interface voor de klasse bal bevatten.
een interface declaratie heeft de vorm:
in het bovenstaande, plus tekens geven klasse methoden aan, of methoden die op de klasse zelf kunnen worden aangeroepen (niet op een instantie), en min tekens geven instantie methoden aan, die alleen op een bepaalde instantie van de klasse kunnen worden aangeroepen. Class methoden hebben ook geen toegang tot instance variabelen.,
de bovenstaande code is ongeveer gelijk aan de volgende C++ interface:
merk op dat instanceMethod2With2Parameters:param2_callName: het interleaving van selectorsegmenten met argument expressies toont, waarvoor er geen direct equivalent is in C/C++.
Return types kunnen elk standaard C type zijn, een pointer naar een generiek Object – C object, een pointer naar een specifiek type object zoals NSArray*, NSImage*, of NSString*, of een pointer naar de klasse waartoe de methode behoort (instancetype). Het standaard return type is het algemene Objective-C type id.,
Methodeargumenten beginnen met een naam die het argument labelt dat deel uitmaakt van de methodenaam, gevolgd door een dubbele punt gevolgd door het verwachte argumenttype tussen haakjes en de argumentnaam. Het label kan worden weggelaten.
een afgeleide van de interface definitie is de categorie, die het mogelijk maakt om methoden toe te voegen aan bestaande klassen.
Implementatiedit
De interface declareert alleen de klasse-interface en niet de methoden zelf: de eigenlijke code wordt geschreven in het implementatiebestand., Implementation (method) bestanden hebben normaal gesproken de bestandsextensie .m
, wat oorspronkelijk betekende”messages”.
@implementation classname+ (return_type)classMethod { // implementation}- (return_type)instanceMethod { // implementation}@end
methoden worden geschreven met behulp van hun interface declaraties.Het vergelijken van Objective-C en c:
- (int)method:(int)i { return ;}
int function(int i) { return square_root(i);}
de syntaxis maakt pseudo-namen van argumenten mogelijk.
interne representaties van een methode variëren tussen de verschillende implementaties van Objective-C., Als myColor van de klasse kleur is, bijvoorbeeld methode-changeColorToRed: green: blue: kan intern worden gelabeld _i_Color_changeColorToRed_green_blue. De i is om te verwijzen naar een instantie methode, met de klasse en vervolgens methode namen toegevoegd en dubbele punten veranderd in underscores. Aangezien de volgorde van parameters deel uitmaakt van de methodenaam, kan deze niet worden gewijzigd om de coderingsstijl of expressie aan te passen zoals met true named parameters.
interne namen van de functie worden echter zelden direct gebruikt. Over het algemeen worden berichten geconverteerd naar functieoproepen die zijn gedefinieerd in de Objective-C Runtime library., Het is niet noodzakelijk bekend op verbindingstijd welke methode zal worden aangeroepen omdat de klasse van de ontvanger (het object dat het bericht wordt verzonden) niet bekend hoeft te zijn tot runtime.
InstantiationEdit
zodra een Objective – C-klasse is geschreven, kan deze worden geïnstalleerd. Dit wordt gedaan door eerst een niet-geïnitialiseerde instantie van de klasse (Een object) toe te wijzen en dan door het te initialiseren. Een object is niet volledig functioneel totdat beide stappen zijn voltooid., Deze stappen moeten worden uitgevoerd met één regel code zodat er nooit een toegewezen object is dat geen initialisatie heeft ondergaan (en omdat het onverstandig is om het tussenresultaat te behouden omdat -init
een ander object kan retourneren dan dat waarop het wordt aangeroepen).,
Instantiatie met de standaard, niet-parameter initializer:
MyObject *foo = init];
Activering met een aangepaste initializer:
MyObject *foo = initWithString:myString];
In het geval waarin er geen aangepaste initialisatie wordt uitgevoerd, de “nieuwe” methode kan vaak gebruikt worden in plaats van de alloc-init berichten:
MyObject *foo = ;
Ook zijn sommige klassen implementeren methode van de klasse initializers., Net als +new
, combineren ze +alloc
en -init
, maar in tegenstelling tot +new
, geven ze een autoreleased instantie terug. Sommige class method initializers nemen parameters:
MyObject *foo = ;MyObject *bar = ;
het allocatiebericht wijst voldoende geheugen toe om alle instance variabelen voor een object te bevatten, stelt alle instance variabelen in op nulwaarden, en verandert het geheugen in een instantie van de klasse; op geen enkel moment tijdens de initialisatie is het geheugen een instantie van de superklasse.,
het init-bericht voert de instelling van de instantie uit bij het aanmaken. De init methode wordt vaak als volgt geschreven:
- (id)init { self = ; if (self) { // perform initialization of object here } return self;}
in het bovenstaande voorbeeld, merk het id
return type op. Dit type staat voor “pointer to any object” in Objective-C (Zie de sectie dynamisch typen).
het initialiseringspatroon wordt gebruikt om ervoor te zorgen dat het object juist geïnitialiseerd wordt door zijn superklasse voordat de init methode zijn initialisatie uitvoert., Het voert de volgende acties uit:
- self = stuurt de superclass instantie een init-bericht en wijst het resultaat toe aan self (pointer naar het huidige object).
- als (self) controleert of de geretourneerde objectwijzer geldig is voordat enige initialisatie wordt uitgevoerd.
- return selfReturns de waarde van self voor de aanroeper.
een niet-geldige object pointer heeft de waarde nihil; conditionele statements zoals ” if ” behandelen nil als een null pointer, dus de initialisatie code zal niet worden uitgevoerd als nil wordt geretourneerd., Als er een fout is in initialisatie moet de init methode de nodige opschoning uitvoeren, inclusief het verzenden van een” release ” bericht naar self, en nil retourneren om aan te geven dat initialisatie is mislukt. Elke controle op dergelijke fouten moet alleen worden uitgevoerd na het aanroepen van de superklasse initialisatie om ervoor te zorgen dat het vernietigen van het object correct zal worden gedaan.
als een klasse meer dan één initialisatiemethode heeft, hoeft slechts één van hen (de “aangewezen initializer”) dit patroon te volgen; anderen zouden de aangewezen initializer moeten aanroepen in plaats van de superclass initializer.,
ProtocolsEdit
In andere programmeertalen worden deze “interfaces”genoemd.
Objective-C werd bij NeXT uitgebreid met het concept van meervoudige overerving van specificatie, maar niet implementatie, door de invoering van protocollen. Dit is een patroon dat haalbaar is als een abstracte meervoudig overgeërfde basisklasse in C++, of als een “interface” (zoals in Java en C#). Objective-C maakt gebruik van Ad hoc protocollen genaamd informele protocollen en compiler-afgedwongen protocollen genaamd formele protocollen.,
een informeel protocol is een lijst van methoden die een klasse kan kiezen om te implementeren. Het is gespecificeerd in de documentatie, omdat het niet aanwezig is in de taal. Informele protocollen worden geà mplementeerd als een categorie (zie hieronder) op NSObject en bevatten vaak optionele methoden, die, indien geà mplementeerd, het gedrag van een klasse kunnen veranderen. Een tekstveldklasse kan bijvoorbeeld een gedelegeerde hebben die een informeel protocol implementeert met een optionele methode voor het automatisch aanvullen van door de gebruiker getypte tekst., Het tekstveld ontdekt of de gedelegeerde die methode implementeert (via reflectie) en, zo ja, roept de methode van de gedelegeerde aan om de functie Automatisch aanvullen te ondersteunen.
een formeel protocol is vergelijkbaar met een interface in Java, C# en Ada 2005. Het is een lijst van methoden die elke klasse zichzelf kan verklaren te implementeren. Versies van Objective – C Voor 2.0 vereisten dat een klasse alle methoden moet implementeren in een protocol dat het zichzelf als adopteert; de compiler zal een fout uitzenden als de klasse niet elke methode uit zijn gedeclareerde protocollen implementeert. Doelstelling C 2.,0 ondersteuning toegevoegd voor het markeren van bepaalde methoden in een protocol optioneel, en de compiler zal de implementatie van optionele methoden niet afdwingen.
een klasse moet worden verklaard dat het protocol wordt uitgevoerd om te worden gezegd dat het ermee in overeenstemming is. Dit is detecteerbaar tijdens runtime. Formele protocollen kunnen geen implementaties bieden; ze verzekeren bellers gewoon dat klassen die voldoen aan het protocol implementaties zullen bieden. In de NeXT/Apple library worden vaak protocollen gebruikt door het systeem voor gedistribueerde objecten om de mogelijkheden weer te geven van een object dat op een extern systeem wordt uitgevoerd.,
de syntaxis
@protocol NSLocking- (void)lock;- (void)unlock;@end
geeft aan dat er het abstracte idee van vergrendelen bestaat. Door in de klassendefinitie te vermelden dat het protocol is geïmplementeerd, beweren
@interface NSLock : NSObject <NSLocking>// ...@end
instanties van NSLock dat zij een implementatie zullen bieden voor de twee instantiemethoden.
Dynamic typingEdit
Objective-C kan, net als Smalltalk, dynamisch typen gebruiken: een object kan een bericht sturen dat niet is opgegeven in zijn interface., Dit kan zorgen voor meer flexibiliteit, omdat een object een bericht kan “vastleggen” en het bericht naar een ander object kan sturen dat op de juiste manier op het bericht kan reageren, of het bericht ook naar een ander object kan sturen. Dit gedrag staat bekend als berichtdoorsturen of delegeren (zie hieronder). Als alternatief kan een foutafhandeling worden gebruikt voor het geval het bericht niet kan worden doorgestuurd. Als een object een bericht niet doorstuurt, erop reageert of een fout verwerkt, dan zal het systeem een runtime-uitzondering genereren., Als berichten worden verzonden naar nul (De null object pointer), zullen ze stilletjes worden genegeerd of een generieke uitzondering oproepen, afhankelijk van compiler opties.
statische typinformatie kan optioneel ook worden toegevoegd aan variabelen. Deze informatie wordt vervolgens gecontroleerd tijdens het compileren. In de volgende vier verklaringen wordt steeds specifiekere typeinformatie verstrekt. De statements zijn equivalent tijdens runtime, maar de extra informatie staat de compiler toe om de programmeur te waarschuwen als het gegeven argument niet overeenkomt met het opgegeven type.,
- (void)setMyValue:(id)foo;
in bovenstaande verklaring kan foo van elke klasse zijn.
- (void)setMyValue:(id<NSCopying>)foo;
in het bovenstaande statement kan foo een instantie zijn van elke klasse die voldoet aan het NSCopying
protocol.
- (void)setMyValue:(NSNumber *)foo;
in het bovenstaande statement moet foo een instantie van de nsnumberklasse zijn.
- (void)setMyValue:(NSNumber<NSCopying> *)foo;
in het bovenstaande statement moet foo een instantie van de nsnumberklasse zijn, en het moet voldoen aan het NSCopying
protocol.,
in Objective-C worden alle objecten weergegeven als pointers, en statische initialisatie is niet toegestaan. Het eenvoudigste object is het type waar id (objc_obj *) naar verwijst, dat alleen een ISA-pointer heeft die zijn klasse beschrijft. Andere types van C, zoals waarden en structs, zijn onveranderd omdat ze geen deel uitmaken van het objectsysteem. Deze beslissing verschilt van het C++ object model, waar struct ‘ s en klassen verenigd zijn.
ForwardingEdit
Objective-C staat het verzenden van een bericht toe aan een object dat mogelijk niet reageert., In plaats van te reageren of simpelweg het bericht te laten vallen, kan een object het bericht doorsturen naar een object dat kan reageren. Forwarding kan worden gebruikt om de implementatie van bepaalde ontwerppatronen te vereenvoudigen, zoals het waarnemingspatroon of het proxy-patroon.
De Objective-C runtime specificeert een paar methoden in Object
Een object dat forwarding wil implementeren hoeft alleen de forwarding methode te overschrijven met een nieuwe methode om het forwarding gedrag te definiëren. De actiemethode performv:: hoeft niet te worden overschreven, omdat deze methode slechts een actie uitvoert gebaseerd op de selector en argumenten., Let op het SEL
type, dat het type berichten is in Objective-C.
opmerking: in OpenStep, Cocoa en GNUstep, de veelgebruikte frameworks van Objective-C, wordt de objectklasse niet gebruikt. De – (void)forwardInvocation: (NSInvocation *)anInvocation methode van de nsobject klasse wordt gebruikt om forwarding uit te voeren.
Exampledit
Hier is een voorbeeld van een programma dat de basis van forwarding demonstreert.
doorstuurserver.h Forwarder.m Ontvanger.h
#import <objc/Object.h>// A simple Recipient object.@interface Recipient : Object- (id)hello;@end
ontvanger.m
#import "Recipient.h"@implementation Recipient- (id)hello { printf("Recipient says hello!\n"); return self;}@end
main.,m
NotesEdit
wanneer gecompileerd met gcc, rapporteert de compiler:
de compiler rapporteert het eerder gemaakte punt, dat doorstuurserver niet reageert op Hallo-berichten. In dit geval is het veilig om de waarschuwing te negeren sinds forwarding is geïmplementeerd. Het uitvoeren van het programma levert deze output op:
$ ./a.outRecipient says hello!
CategoriesEdit
tijdens het ontwerp van Objective-C was een van de belangrijkste zorgen de onderhoudbaarheid van grote codebasissen., De ervaring in de wereld van de gestructureerde programmering had geleerd dat een van de belangrijkste manieren om de code te verbeteren was om het op te splitsen in kleinere stukken. Objective-C Leende en breidde het concept van categorieën uit Smalltalk implementaties om te helpen met dit proces.
bovendien worden de methoden binnen een categorie tijdens run-time aan een klasse toegevoegd. Dus, categorieën staan de programmeur toe om methoden toe te voegen aan een bestaande klasse – een open klasse – zonder de noodzaak om die klasse te compileren of zelfs toegang te hebben tot de broncode., Als een systeem bijvoorbeeld geen spellingcontrole bevat in zijn String-implementatie, kan het worden toegevoegd zonder de String-broncode te wijzigen.
methoden binnen categorieën worden niet te onderscheiden van de methoden in een klasse wanneer het programma wordt uitgevoerd. Een categorie heeft volledige toegang tot alle instance variabelen binnen de klasse, inclusief privé variabelen.
als een categorie een methode aangeeft met dezelfde handtekening als een bestaande methode in een klasse, wordt de methode van de categorie gebruikt. Zo kunnen categorieën niet alleen methoden toevoegen aan een klasse, maar ook bestaande methoden vervangen., Deze functie kan worden gebruikt om bugs in andere klassen op te lossen door hun methoden te herschrijven, of om een globale verandering te veroorzaken in het gedrag van een klasse binnen een programma. Als twee categorieën methoden hebben met dezelfde naam maar verschillende methode handtekeningen, is het niet gedefinieerd welke categorie methode wordt aangenomen.
andere talen hebben geprobeerd deze functie op verschillende manieren toe te voegen. TOM ging een stap verder met het Objective-C-systeem en liet ook variabelen toe. Andere talen hebben in plaats daarvan prototype-gebaseerde oplossingen gebruikt, de meest opvallende is Self.
De C# en Visual Basic.,NET languages implementeren oppervlakkig vergelijkbare functionaliteit in de vorm van uitbreidingsmethoden, maar deze hebben geen toegang tot de privévariabelen van de klasse. Ruby en verschillende andere dynamische programmeertalen verwijzen naar de techniek als “monkey patching”.
Logtalk implementeert een concept van categorieën (als eersteklas entiteiten) dat de functionaliteit van Objective-C-categorieën omvat (Logtalk-categorieën kunnen ook worden gebruikt als fijnkorrelige eenheden van samenstelling bij het definiëren van bijvoorbeeld nieuwe klassen of prototypes; met name kan een logtalk-categorie vrijwel worden geïmporteerd door een willekeurig aantal klassen en prototypes).,
voorbeeld gebruik van categoriesEdit
Dit voorbeeld bouwt een gehele klasse op, door eerst een basisklasse te definiëren met alleen accessormethoden geà mplementeerd, en twee categorieën toe te voegen, rekenkunde en Display, die de basisklasse uitbreiden. Hoewel categorieën toegang hebben tot de private data leden van de basisklasse, is het vaak een goede gewoonte om toegang te krijgen tot deze private data leden via de accessor methoden, wat helpt om Categorieën onafhankelijker te houden van de basis klasse. Het implementeren van dergelijke accessors is een typisch gebruik van categorieën. Een andere is om categorieën te gebruiken om methoden toe te voegen aan de basisklasse., Het wordt echter niet als een goede praktijk beschouwd om categorieën te gebruiken voor het overschrijven van subklassen, ook bekend als monkey patching. Informele protocollen worden geïmplementeerd als een categorie op de basis nsobject klasse. Bestanden die categorieën bevatten die basisklassen uitbreiden, krijgen de naam BaseClass+ExtensionClass.h.
geheel getal.h
#import <objc/Object.h>@interface Integer : Object { int integer;}- (int)integer;- (id)integer:(int)_integer;@end
Integer.m Integer+rekenkunde.h
#import "Integer.h"@interface Integer (Arithmetic)- (id) add: (Integer *) addend;- (id) sub: (Integer *) subtrahend;@end
Integer+rekenkunde.m Integer + Display.h
#import "Integer.h"@interface Integer (Display)- (id) showstars;- (id) showint;@end
Integer+Display.m main.,m
NotesEdit
compilatie wordt bijvoorbeeld uitgevoerd door:
gcc -x objective-c main.m Integer.m Integer+Arithmetic.m Integer+Display.m -lobjc
men kan experimenteren door het weglaten van de #import ” Integer+Arithmetic.h ” en lijnen en het weglaten van Integer + rekenkunde.m in Compilatie. Het programma zal nog steeds draaien. Dit betekent dat het mogelijk is om toegevoegde categorieën te mixen en matchen als dat nodig is; als een categorie geen enkele mogelijkheid nodig heeft, kan het simpelweg niet gecompileerd worden.
PosingEdit
Objective-C staat toe dat een klasse een andere klasse binnen een programma volledig vervangt. Van de vervangende klasse wordt gezegd dat ze zich “voordoen als” de doelklasse.,
Klasse poseren is verouderd verklaard met Mac OS X v10. 5, en is niet beschikbaar in de 64-bit runtime. Soortgelijke functionaliteit kan worden bereikt door middel van methode swizzling in categorieën, dat swaps een methode implementatie met een andere die dezelfde handtekening hebben.
voor de versies die nog steeds poseren ondersteunen, worden alle berichten die naar de doelklasse worden verzonden in plaats daarvan ontvangen door de poseren klasse. Er zijn verschillende beperkingen:
- Een klasse mag zich slechts voordoen als een van haar directe of indirecte superklassen.,
- de posing-klasse mag geen nieuwe instantievariabelen definiëren die afwezig zijn in de doelklasse (hoewel het methoden kan definiëren of overschrijven).
- de doelklasse heeft mogelijk geen berichten ontvangen vóór het poseren.
poseren, vergelijkbaar met categorieën, maakt globale vergroting van bestaande klassen mogelijk. Poseren staat twee kenmerken toe die niet voorkomen in categorieën:
- Een poseren klasse kan overschrijdende methoden aanroepen via super, waardoor de implementatie van de doelklasse wordt geïntegreerd.
- een poserende klasse kan methoden die in categorieën zijn gedefinieerd overschrijven.,
bijvoorbeeld
Dit onderschept elke aanroep van setMainMenu naar NSApplication.
#importEdit
in de C-taal zorgt de #include
pre-compileer directive ervoor dat de inhoud van een bestand op dat moment in de bron wordt ingevoegd. Objective-C heeft de #import
richtlijn, gelijkwaardig, behalve dat elk bestand slechts één keer per compilatie-eenheid wordt opgenomen, zodat er geen bewakers hoeven te worden opgenomen.