In dit hoofdstuk gaan we dieper in op Objective-C-methoden dan in eerdere hoofdstukken. Dit omvat een grondige bespreking van voorbeeldmethoden, klassemethoden, belangrijke ingebouwde methoden, overerving, naamgevingsconventies en algemene ontwerppatronen.
We hebben in dit boek zowel met instantie- als met klassemethoden gewerkt, maar laten we een moment nemen om de twee belangrijkste categorieën methoden in Objective-C te formaliseren:
Zoals we vaak hebben gezien, worden de instantiemethoden aangeduid met een koppelteken vóór de naam van de methode, terwijl klassemethoden worden voorafgegaan door een plusteken. Laten we bijvoorbeeld een vereenvoudigde versie van onze versie nemen Person.h
het dossier:
@interface Persoon: NSObject @property (kopie) NSString * naam; - (ongeldig) zeg Hallo; + (Persoon *) personWithName: (NSString *) naam; @einde
Op dezelfde manier moeten de bijbehorende implementatiemethoden ook worden voorafgegaan door een koppelteken of een plusteken. Dus een minimum Person.m
kan er ongeveer zo uitzien:
#import "Person.h" @implementation Persoon @synthesize name = _name; - (ongeldig) sayHello NSLog (@ "HELLO"); + (Persoon *) personWithName: (NSString *) naam Person * person = [[Person alloc] init]; person.name = naam; terugkeer persoon; @end
De zeg hallo
methode kan worden aangeroepen door instanties van de Persoon
klasse, terwijl de personWithName
methode kan alleen door de klasse zelf worden aangeroepen:
Persoon * p1 = [Persoon personWithName: @ "Frank"]; // Class-methode. [p1 sayHello]; // Instantiemethode.
Het meeste hiervan zou je nu wel bekend moeten zijn, maar nu hebben we de gelegenheid om te praten over enkele van de unieke conventies in Objective-C.
In elke objectgeoriënteerde omgeving is het belangrijk om toegang te hebben tot methoden uit de bovenliggende klasse. Objective-C gebruikt een zeer vergelijkbaar schema als C #, behalve in plaats van baseren
, het gebruikt de super
trefwoord. Bijvoorbeeld de volgende implementatie van zeg hallo
zou weergeven HALLO
in het uitvoerpaneel en bel vervolgens de ouderklasse 'versie van zeg hallo
:
- (ongeldig) sayHello NSLog (@ "HELLO"); [super sayHello];
In tegenstelling tot C # hoeven override-methoden niet expliciet als zodanig te worden gemarkeerd. Je zult dit zien met zowel de in het
en dealloc
methoden die in de volgende sectie worden besproken. Hoewel deze zijn gedefinieerd op de NSObject
klasse, de compiler klaagt niet wanneer je je eigen maakt in het
en dealloc
methoden in subklassen.
Initialisatiemethoden zijn vereist voor alle objecten: een nieuw toegewezen object wordt niet beschouwd als "gereed voor gebruik" totdat een van de initialisatiemethoden is aangeroepen. Ze zijn de plaats om standaardwaarden in te stellen voor bijvoorbeeld variabelen en om de status van het object anders in te stellen. De NSObject
klasse definieert een standaardwaarde in het
methode die niets doet, maar het is vaak handig om je eigen te maken. Bijvoorbeeld een gebruik in het
implementatie voor onze Schip
klasse kan standaardwaarden toewijzen aan een geroepen instantievariabele _ammo
:
- (id) init self = [super init]; if (self) _ammo = 1000; terugkeer zelf;
Dit is de canonieke manier om een gebruik te definiëren in het
methode. De zelf
trefwoord is het equivalent van C # 's deze
-het wordt gebruikt om te verwijzen naar de instantie die de methode aanroept, die het voor een object mogelijk maakt om berichten naar zichzelf te verzenden. Zoals je kunt zien, allemaal in het
methoden zijn vereist om de instantie te retourneren. Dit is wat het mogelijk maakt om de [[Ship alloc] init]
syntaxis om het exemplaar toe te wijzen aan een variabele. Merk ook op dat omdat het NSObject
interface verklaart de in het
methode is het niet nodig om een in het
verklaring aan Ship.h
.
Hoewel eenvoudig in het
methoden zoals die in de vorige steekproef zijn nuttig voor het instellen van standaardwaarden van de instantievariabele, het is vaak handiger om parameters door te geven aan een initialisatiemethode:
- (id) initWithAmmo: (unsigned int) theAmmo self = [super init]; if (self) _ammo = theAmmo; terugkeer zelf;
Als u afkomstig bent van een C # -achtergrond, kunt u zich ongemakkelijk voelen bij de initWithAmmo
methode naam. Je zou waarschijnlijk verwachten het te zien ammunitie
parameter gescheiden van de werkelijke methode naam zoals void init (uint-munitie)
; De naamgeving van Objective-C is echter gebaseerd op een geheel andere filosofie.
Bedenk dat het doel van Objective-C is om een API zo beschrijvend mogelijk te maken, zodat er absoluut geen verwarring bestaat over wat een methode-call gaat doen. Je kunt een methode niet als een afzonderlijke entiteit van zijn parameters beschouwen - ze zijn een enkele eenheid. Deze ontwerpbeslissing komt feitelijk tot uiting in de implementatie van Objective-C, die geen onderscheid maakt tussen een methode en zijn parameters. Intern is de naam van een methode eigenlijk de samengevoegde parameterlijst.
Bekijk bijvoorbeeld de volgende drie methodeaangiften. Merk op dat de tweede en derde geen ingebouwde methoden van zijn NSObject
, dus jij do moet u ze toevoegen aan de klasse-interface voordat u ze implementeert.
- (Id) init; - (id) initWithAmmo: (unsigned int) theAmmo; - (id) initWithAmmo: (unsigned int) theAmmo captain: (Person *) theCaptain;
Hoewel dit lijkt op overbelasting van de methode, is dit technisch gezien niet het geval. Dit zijn geen variaties op de in het
methode - het zijn allemaal volledig onafhankelijke methoden met verschillende namen van methoden. De namen van deze methoden zijn als volgt:
init initWithAmmo: initWithAmmo: captain:
Dit is de reden waarom je de notatie ziet indexOfObjectWithOptions: passingTest:
en indexOfObjectAtIndexes: options: passingTest:
voor het verwijzen naar methoden in de officiële Objective-C documentatie (ontleend aan NSArray).
Vanuit praktisch standpunt betekent dit dat de eerste parameter van uw methoden altijd moet worden beschreven met de "primaire" methode naam. Dubbelzinnige methoden zoals de volgende worden meestal afgekeurd door Objective-C programmeurs:
- (id) schieten: (schip *) aShip;
In plaats daarvan moet u een voorzetsel gebruiken om de eerste parameter in de naam van de methode op te nemen, zoals:
- (id) shootOtherShip: (schip *) aShip;
Inclusief beide OtherShip
en een schip
in de methode definitie lijkt overbodig, maar vergeet niet dat de een schip
argument wordt alleen intern gebruikt. Iemand die de methode noemt gaat zoiets schrijven shootOtherShip: discoveryOne
, waar discoveryOne
is de variabele die het schip bevat dat u wilt fotograferen. Dit is precies het soort breedsprakigheid waar Objective-C-ontwikkelaars naar streven.
In aanvulling op de in het
methode voor initialiseren instanties, Objective-C biedt ook een manier om in te stellen klassen. Voordat objecttypen worden aangeroepen of instanties van objecten worden gemaakt, roept de runtime Objective-C de initialiseren
klassenmethode van de betreffende klasse. Dit geeft u de mogelijkheid om eventuele statische variabelen te definiëren voordat iemand de klasse gebruikt. Een van de meest voorkomende use-cases hiervoor is het opzetten van singletons:
static Ship * _sharedShip; + (void) initialiseer if (self == [Ship class]) _sharedShip = [[self alloc] init]; + (Verzenden *) sharedShip return _sharedShip;
Voor de eerste keer [Ship sharedShip]
wordt aangeroepen, wordt de looptijd aangeroepen [Ship initialize]
, wat ervoor zorgt dat de singleton gedefinieerd is. De statische variabel-modifier heeft hetzelfde doel als in C #, want het maakt een klasse-niveau variabele in plaats van een instantievariabele. De initialiseren
methode wordt slechts één keer aangeroepen, maar het wordt aangeroepen op alle superklassen, dus je moet ervoor zorgen dat je variabelen op klasniveau niet meerdere keren initialiseert. Dit is waarom we de zelf == [scheepsklasse]
voorwaardelijk om zeker te zijn _shareShip
wordt alleen toegewezen in de Schip
klasse.
Merk ook op dat de binnenkant van een klassenmethode de zelf
trefwoord verwijst naar de klasse zelf, niet naar een instantie. Zo, [zelftoewijzing]
in het laatste voorbeeld is het equivalent van [Ship alloc]
.
De logische tegenhanger van de initialisatiemethode van een instantie is de dealloc
methode. Deze methode wordt aangeroepen wanneer het referentietelling nul bereikt en het onderliggende geheugen op het punt staat te worden verwijderd.
Als u handmatig geheugenbeheer gebruikt (niet aanbevolen), moet u eventuele instantievariabelen vrijgeven die uw object heeft toegewezen in de dealloc
methode. Als u geen instantievariabelen vrijgeeft voordat uw object buiten het bereik valt, heeft u bengelende verwijzingen naar uw instantievariabelen, wat betekent dat het geheugen leeg is wanneer een exemplaar van de klasse wordt vrijgegeven. Bijvoorbeeld, als onze Schip
klasse toegewezen een variabele genaamd _gun
in zijn in het
methode, zou je het moeten vrijgeven dealloc
. Dit wordt aangetoond in het volgende voorbeeld (Gun.h
bevat een lege interface die eenvoudig de definieert geweer
klasse):
#import "Ship.h" #import "Gun.h" @implementation Ship BOOL _gunIsReady; Gun * _gun; - (id) init self = [super init]; if (zelf) _gun = [[Gun alloc] init]; terugkeer zelf; - (void) dealloc NSLog (@ "Deallocating a Ship"); [_gun-release]; [super dealloc]; @end
Je kan de ... zien dealloc
methode in actie door een Schip
en het vrijgeven, zoals zo:
int main (int argc, const char * argv []) @autoreleasepool Ship * ship = [[Ship alloc] init]; [schip autorelease]; NSLog (@ "Schip zou nog moeten bestaan in autoreleasepool"); NSLog (@ "Schip moet nu worden vrijgegeven); retourneer 0;
Dit toont ook aan hoe automatisch vrijgegeven objecten werken. De dealloc
methode zal niet worden aangeroepen tot het einde van de @autoreleasepool
blokkeren, dus de vorige code moet het volgende weergeven:
Schip zou nog steeds moeten bestaan in autoreleasepool. Een scheepsallocatie anders zou nu al moeten worden verwijderd
Merk op dat de eerste NSLog ()
bericht in hoofd()
is weergegeven voor die in de dealloc
methode, hoewel het werd genoemd na de autorelease
telefoontje.
Als u echter automatische referentietelling gebruikt, worden al uw instantievariabelen automatisch verwijderd, en [super dealloc]
zal ook voor jou worden opgeroepen (je zou het nooit expliciet moeten noemen). Het enige waar u zich zorgen over hoeft te maken, zijn niet-objectvariabelen zoals buffers gemaakt met C's malloc ()
.
Net zoals in het
, je hoeft geen a te implementeren dealloc
methode als uw object geen speciale behandeling nodig heeft voordat het wordt vrijgegeven. Dit is vaak het geval voor automatische referentie-telomgevingen.
Een grote hindernis voor C # -ontwikkelaars die overgaan op Objective-C is het schijnbare gebrek aan privémethoden. In tegenstelling tot C # zijn alle methoden in een Objective-C-klasse toegankelijk voor derden; het is echter mogelijk om wedijveren het gedrag van privémethoden.
Onthoud dat clients alleen de interface van een klasse importeren (dat wil zeggen de headerbestanden) - ze mogen de onderliggende implementatie nooit zien. Dus door nieuwe methoden toe te voegen in de implementatie bestand zonder ze op te nemen in de interface, we kunnen methoden effectief verbergen voor andere objecten. Hoewel dit meer op conventies gebaseerde dan 'echte' privémethoden is, maar het is in wezen dezelfde functionaliteit: proberen een methode aan te roepen die niet in een interface is gedeclareerd, resulteert in een compilerfout.
Probeert een "private" methode aan te roepenStel dat u bijvoorbeeld een privébericht moet toevoegen prepareToShoot
methode om de Schip
klasse. Het enige dat u hoeft te doen, is om het weg te laten Ship.h
tijdens het toevoegen aan Ship.m
:
// Ship.h @interface Schip: NSObject @property (weak) Persoon * kapitein; - (ongeldig) schieten; @einde
Dit verklaart een openbare methode genaamd schieten
, die de privé gebruiken prepareToShoot
methode. De bijbehorende implementatie kan er ongeveer zo uitzien:
// Ship.m #import "Ship.h" @implementation Ship BOOL _gunIsReady; @synthesize captain = _captain; - (void) shoot if (! _gunIsReady) [self prepareToShoot]; _gunIsReady = YES; NSLog (@ "Firing!"); - (void) prepareToShoot // Voer enkele privéfunctionaliteit uit. NSLog (@ "Het hoofdwapen voorbereiden ..."); @end
Vanaf Xcode 4.3 kunt u privémethoden definiëren overal in de implementatie. Als u de privémethode gebruikt voordat de compiler deze heeft gezien (zoals in het vorige voorbeeld), controleert de compiler de rest van het implementatieblok voor de methode-definitie. Voorafgaand aan Xcode 4.3 moest je een privémethode definiëren voor het werd ergens anders in het bestand gebruikt, of doorstuur het met een klasse extensie.
Klasse-extensies zijn een speciaal geval van categorieën, die in het komende hoofdstuk worden gepresenteerd. Net zoals er geen manier is om een methode als privé te markeren, is er geen manier om een methode te markeren als beschermd; Zoals we in het volgende hoofdstuk zullen zien, bieden categorieën echter een krachtig alternatief voor beschermde methoden.
Selectoren zijn de methode van Objective-C om methoden weer te geven. Hiermee kunt u een van de methoden van een object dynamisch "selecteren". Deze methoden kunnen worden gebruikt om tijdens runtime naar een methode te verwijzen, een methode door te geven aan een andere functie en uit te zoeken of een object een bepaalde methode heeft. Voor praktische doeleinden kunt u een selector zien als een alternatieve naam voor een methode.
Ontwikkelaarsvertegenwoordiging van een methode versus de representatie van Objective-CIntern gebruikt Objective-C een uniek nummer om elke methode naam die uw programma gebruikt te identificeren. Bijvoorbeeld een methode genaamd zeg hallo
kan vertalen naar 4984331082
. Deze ID wordt a genoemd keuzeschakelaar, en het is een veel efficiëntere manier voor de compiler om naar methoden te verwijzen dan de volledige tekenreeksrepresentatie. Het is belangrijk om te begrijpen dat een selector alleen de methode vertegenwoordigt naam-geen specifieke methode-implementatie. Met andere woorden, a zeg hallo
methode gedefinieerd door de Persoon
klasse heeft dezelfde selector als een zeg hallo
methode gedefinieerd door de Schip
klasse.
De drie belangrijkste hulpmiddelen voor het werken met selectors zijn:
@ selector ()
- Retourneer de selector die is gekoppeld aan de naam van een broncodemethode.NSSelectorFromString ()
- Retourneer de selector die is gekoppeld aan de tekenreeksrepresentatie van een methode naam. Deze functie maakt het mogelijk om de methode naam tijdens runtime te definiëren, maar het is minder efficiënt dan @ selector ()
.NSStringFromSelector ()
- Retourneer de tekenreeksrepresentatie van een methode uit een selector.Zoals je ziet, zijn er drie manieren om een methode-naam in Objective-C weer te geven: als broncode, als een tekenreeks of als een selector. Deze conversiefuncties worden grafisch weergegeven in de volgende afbeelding:
Conversie tussen broncode, strings en selectorsSelectoren worden opgeslagen in een speciaal gegevenstype met de naam SEL
. Het volgende fragment toont het basisgebruik van de drie conversiefuncties in de vorige afbeelding:
int main (int argc, const char * argv []) @autoreleasepool SEL selector = @selector (sayHello); NSLog (@ "% @", NSStringFromSelector (selector)); if (selector == NSSelectorFromString (@ "sayHello")) NSLog (@ "De selectors zijn gelijk!"); retourneert 0;
Eerst gebruiken we de @ selector ()
richtlijn om de selector voor een methode genaamd zeg hallo
, wat een broncode-weergave is van een methode naam. Merk op dat je kunt slagen ieder methode naam voor @ selector ()
-het hoeft niet ergens anders in je programma te bestaan. Vervolgens gebruiken we de NSStringFromSelector ()
functie om de selector terug te converteren naar een tekenreeks, zodat we deze in het uitvoerpaneel kunnen weergeven. Ten slotte laat de voorwaardelijke zien dat selectors een één-op-één correspondentie hebben met de namen van de methoden, ongeacht of u ze vindt via hard-coded methode namen of strings.
Het vorige voorbeeld gebruikt een eenvoudige methode zonder parameters, maar het is belangrijk om methoden te kunnen doorgeven die dat zijn do accepteer parameters. Herinner dat de naam van een methode bestaat uit de naam van de primaire methode die aaneengeschakeld is met alle parameternamen. Bijvoorbeeld een methode met de handtekening
- (ongeldig) sayHelloToPerson: (Persoon *) aPerson withGreeting: (NSString *) aGreeting;
zou een methode hebben naam van:
sayHelloToPerson: withGreeting:
Dit is wat je zou doorgeven @ selector ()
of NSSelectorFromString ()
om de identifier voor die methode te retourneren. Selectors werken alleen met de methode namen (geen handtekeningen), dus dat is er wel niet een één-op-één-correspondentie tussen selectors en handtekeningen. Als gevolg hiervan, de methode naam in het laatste voorbeeld komt ook een handtekening overeen met verschillende gegevenstypen, waaronder de volgende:
- (void) sayHelloToPerson: (NSString *) aName withGreeting: (BOOL) useGreeting;
De breedsprakigheid van de naamgevingsconventies van Objective-C vermijdt de meest verwarrende situaties; selectors voor methoden met één parameter kunnen echter nog steeds lastig zijn, omdat het toevoegen van een dubbele punt aan de methode naam dit feitelijk verandert in een totaal verschillend methode. In de volgende voorbeeld neemt de eerste methode naam bijvoorbeeld geen parameter, terwijl de tweede naam:
zeg Hallo zeg Hallo:
Nogmaals, het benoemen van conventies gaat een lange weg naar het elimineren van verwarring, maar je moet nog steeds zeker weten dat het nodig is om een dubbele punt toe te voegen aan het einde van een methode naam. Dit is een veelvoorkomend probleem als u nieuw bent bij selectors en het kan moeilijk zijn om fouten te debuggen, omdat een trailing colon nog steeds een perfect geldige methode naam creëert.
Natuurlijk, een selector opnemen in een SEL
variabele is relatief nutteloos zonder de mogelijkheid om het later uit te voeren. Omdat een selector slechts een methode is naam (geen implementatie), het moet altijd aan een object worden gekoppeld voordat je het kunt bellen. De NSObject
klasse definieert een performSelector:
methode voor dit specifieke doel.
[joe performSelector: @selector (sayHello)];
Dit is het equivalent van bellen zeg hallo
direct aan joe
:
[Joe SayHello];
Voor methoden met een of twee parameters, kunt u de gerelateerde gebruiken performSelector: withObject:
en performSelector: withObject: withObject:
methoden. De volgende methode-implementatie:
- (void) sayHelloToPerson: (Persoon *) aPerson NSLog (@ "Hello,% @", [aPerson name]);
kan dynamisch worden genoemd door de een persoon
argument voor de performSelector: withObject:
methode, zoals hier aangetoond:
[joe performSelector: @selector (sayHelloToPerson :) withObject: bill];
Dit is het equivalent van het direct doorgeven van de parameter aan de methode:
[joe zegHelloToPerson: factuur];
Evenzo, de performSelector: withObject: withObject:
methode laat je twee parameters doorgeven aan de doelmethode. Het enige nadeel hiervan is dat alle parameters en de retourwaarde van de methode objecten moeten zijn - ze werken niet met primitieve C-gegevenstypen zoals int
, vlotter
, enz. Als u deze functionaliteit nodig hebt, kunt u het primitieve type in een van de vele wrapper-klassen van Objective-C stoppen (bijv.., NSNumber
) of gebruik het NSInvocation-object om een volledige methodeaanroep in te kapselen.
Het is niet mogelijk om een selector uit te voeren op een object dat de bijbehorende methode niet heeft gedefinieerd. Maar in tegenstelling tot statische methode-aanroepen, is het niet mogelijk om tijdens compilatie vast te stellen of performSelector:
zal een fout melden. In plaats daarvan moet u controleren of een object tijdens runtime op een selector kan reageren met de toepasselijke naam respondsToSelector:
methode. Het keert eenvoudig terug JA
of NEE
afhankelijk van of het object de selector kan uitvoeren:
SEL methodToCall = @selector (sayHello); if ([joe reageertToSelector: methodToCall]) [joe performSelector: methodToCall]; else NSLog (@ "Joe weet niet hoe% @ moet worden uitgevoerd.", NSStringFromSelector (methodToCall));
Als uw selectors dynamisch worden gegenereerd (bijv methodToCall
is geselecteerd uit een lijst met opties) of u hebt geen controle over het doelobject (bijv., joe
kan een van verschillende soorten objecten zijn), het is belangrijk om deze controle uit te voeren voordat u probeert te bellen performSelector:
.
Het hele idee achter selectors is om methoden te kunnen doorgeven, net zoals je objecten omzeilt. Dit kan bijvoorbeeld worden gebruikt om dynamisch een "actie" voor een te definiëren Persoon
object om later in het programma uit te voeren. Overweeg bijvoorbeeld de volgende interface:
Inclusief codevoorbeeld: Selectors
@interface Persoon: NSObject @property (kopie) NSString * naam; @property (zwak) Persoon * vriend; @property SEL-actie; - (ongeldig) zeg Hallo; - (void) sayGoodbye; - (void) coerceFriend; @einde
Samen met de bijbehorende implementatie:
#import "Person.h" @implementation Persoon @synthesize name = _name; @synthesize friend = _friend; @synthesize action = _action; - (void) sayHello NSLog (@ "Hello, says% @.", _name); - (void) sayGoodbye NSLog (@ "Goodbye, says% @.", _name); - (void) coerceFriend NSLog (@ "% @ staat op het punt om% @ iets te laten doen.", _name, [_friend name]); [_friend performSelector: _action]; @end
Zoals je kunt zien, het bellen van de coerceFriend
methode dwingt a verschillend object om een willekeurige actie uit te voeren. Hiermee kunt u een vriendschap en een gedrag in een vroeg stadium in uw programma configureren en wachten tot een bepaalde gebeurtenis plaatsvindt voordat de actie wordt geactiveerd:
#importeren#import "Person.h" NSString * askUserForAction () // In de echte wereld zou dit enkele // gebruikersinvoer bevatten om te bepalen welke methode moet worden aangeroepen. NSString * theMethod = @ "sayGoodbye"; keer terug de Methode; int main (int argc, const char * argv []) @autoreleasepool // Maak een persoon en bepaal een uit te voeren actie. Persoon * joe = [[Person alloc] init]; joe.name = @ "Joe"; Persoon * factuur = [[Person alloc] init]; bill.name = @ "Factuur"; joe.friend = bill; joe.action = NSSelectorFromString (askUserForAction ()); // Wacht op een evenement ... // Voer de actie uit. [joe coerceFriend]; retourneer 0;
Dit is bijna precies hoe gebruikersinterfacecomponenten in iOS worden geïmplementeerd. Als u bijvoorbeeld een knop had, zou u deze configureren met een doelobject (bijv., vriend
) en een actie (bijv., actie
). Wanneer de gebruiker vervolgens op de knop drukt, kan deze gebruiken performSelector:
om de gewenste methode op het juiste object uit te voeren. Zowel het object toestaan en de methode om onafhankelijk te variëren, biedt een aanzienlijke flexibiliteit: de knop kan letterlijk elke actie uitvoeren met elk object zonder de klasse van de knop op enigerlei wijze te veranderen. Dit vormt ook de basis van het Target-Action ontwerppatroon, waarop in de iOS bondig begeleidend boek.
In dit hoofdstuk hebben we voorbeelden van methoden en klassen behandeld, samen met enkele van de belangrijkste ingebouwde methoden. We hebben nauw samengewerkt met selectors, wat een manier is om te verwijzen naar methodamen als broncode of strings. We hebben ook een beknopt overzicht gegeven van het ontwerppatroon van Target-Action, dat een integraal onderdeel is van iOS- en OS X-programmering.
Het volgende hoofdstuk bespreekt een alternatieve manier om privé- en beschermde methoden te maken in Objective-C.
Deze les vertegenwoordigt een hoofdstuk uit Objective-C bondig, een gratis eBoek van het team van Syncfusion.