Objective-C — een programmeertaal met dynamische berichtendispatchering, gemaakt door Brad Cox in de jaren 1980. Apple koos Objective-C als de primaire taal voor NeXTSTEP en later voor iOS SDK. Programming With Objective-C — inleiding tot berichtensyntaxis en geheugenbeheer.
Belangrijkste
Objective-C — een programmeertaal die C uitbreidt met objectgeoriënteerde programmeermogelijkheden in Smalltalk-stijl. Objective-C-code wordt via LLVM of GCC gecompileerd naar native machinecode, met volledige achterwaartse compatibiliteit met C — elke C-code is correct in Objective-C.
Apple nam NeXT (samen met Objective-C) over in 1997. De taal werd de basis van Cocoa en Cocoa Touch — de frameworks voor macOS en iOS. Sinds 2014 promoot Apple Swift als vervanging, maar Objective-C blijft cruciaal voor legacy-projecten en sommige systeemframeworks. Volgens Apple (WWDC 2024) bevat ongeveer 35% van de apps in de App Store nog steeds Objective-C-code.
Belangrijkste kenmerk — dynamische runtime. In tegenstelling tot Swift, waar methodeaanroepen tijdens compilatie worden opgelost, verzendt Objective-C berichten tijdens uitvoering via de functie objc_msgSend. Dit maakt het mogelijk om methoden dynamisch te overschrijven (method swizzling), klassen dynamisch toe te voegen en forward invocation te gebruiken voor niet-bestaande selectors.
Elke C-code is correct in Objective-C. De objectgeoriënteerde bovensbouw voegt klassen (@interface/@implementation), categorieën, protocollen (@protocol) en dynamische typering (id) toe. Bestanden hebben extensies .m (implementatie) en .h (headers).
Berichtensyntaxis — het belangrijkste verschil van Objective-C met C-achtige talen. In plaats van object.method(argument) wordt [object method:argument] gebruikt. Elk bericht gaat door objc_msgSend, die dynamisch de implementatie van de methode in de runtime zoekt.
// Berichtensyntaxis met benoemde parameters
NSString *greeting = [NSString stringWithFormat:@"Hello, %@", name];
// Geneste berichten
NSArray *sortedArray = [[array sortedArrayUsingSelector:@selector(compare:)] copy];
// Typecontrole via instrospectie
if ([object isKindOfClass:[UIView class]]) {
UIView *view = (UIView *)object;
view.backgroundColor = [UIColor redColor];
}Dynamic dispatch maakt het mogelijk om methoden in runtime te overschrijven (method swizzling) — een krachtige maar gevaarlijke techniek. Frameworks zoals AFNetworking en Aspects gebruiken bijvoorbeeld swizzling voor het onderscheppen van URLSession-aanroepen. Apple waarschuwt: swizzling kan de werking van systeemframeworks verstoren bij verkeerd gebruik.
Categories — een unieke mogelijkheid van Objective-C om methoden toe te voegen aan bestaande klassen (inclusief systeemklassen zoals NSString en UIView) zonder overerving en zonder toegang tot broncode. Categorieën worden gedeclareerd via @interface ClassName (CategoryName).
// Bestand UIColor+Hex.h — categorie voor UIColor
@interface UIColor (Hex)
+ (instancetype)colorWithHex:NSUIntegerhex;
@end
// Bestand UIColor+Hex.m — implementatie
@implementation UIColor (Hex)
+ (instancetype)colorWithHex:NSUIntegerhex {
CGFloat r = ((hex >> 16) & 0xFF) / 255.0;
CGFloat g = ((hex >> 8) & 0xFF) / 255.0;
CGFloat b = (hex & 0xFF) / 255.0;
return [self colorWithRed:r green:g blue:b alpha:1.0];
}
@endExtensions (Class Extension) — een speciaal soort categorie, gedeclareerd in .m-bestand zonder naam: @interface ClassName (). In tegenstelling tot categorieën kunnen extensions niet alleen methoden, maar ook ivar (instantievariabelen) en property toevoegen. Extensions worden gebruikt om interne API te verbergen voor externe modules.
Blocks — anonieme functies in Objective-C die variabelen uit de externe scope vastleggen. Syntaxis van blokken: ^(int x) { return x * 2; }. Blocks worden gebruikt in UIKit voor callback-handlers, in Grand Central Dispatch voor asynchrone taken en in NSArray/NSDictionary-collecties voor functionele bewerkingen.
// Declaratie van bloktype
typedef void (^CompletionBlock)(BOOL success, NSError *error);
// Blok als parameter
- (void)fetchDataWithCompletion:(CompletionBlock)completion {
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
BOOL result = [weakSelf processData];
if (completion) {
completion(result, nil);
}
});
}Geheugenbeheer in blokken is van cruciaal belang. Blokken leggen self vast met een sterke referentie, wat een retain cycle creëert bij direct gebruik. Oplossing — __weak typeof(self) weakSelf = self, met vervolgcontrole binnen het blok. Dit probleem is volledig opgelost in Swift via capture lists [weak self].
Objective-C heeft de weg afgelegd van MRC (Manual Reference Counting) naar ARC (Automatic Reference Counting). In MRC riep de programmeur handmatig retain (teller verhogen), release (verlagen) en autorelease (uitgestelde release) aan. Fouten in deze aanroepen leidden tot geheugenlekken of crashes door dangling pointers.
| Bewerking | MRC | ARC |
|---|---|---|
| Object maken | [[Object alloc] init] | [[Object alloc] init] |
| Referentie behouden | [object retain] | Automatisch |
| Vrijgeven | [object release] | Automatisch |
| Automatisch vrijgeven | [object autorelease] | Automatisch (niet vereist) |
| Weak referentie | __weak bestond niet | __weak (automatische nil) |
ARC werd geïntroduceerd in Xcode 4.2 en LLVM 3.0 (2011). De compiler voegt automatisch retain/release in tijdens compilatie door de levensduur van objecten te analyseren. ARC is geen garbage collection — het is statische analyse met automatische invoegingen. Objective-C ARC is compatibel met Swift ARC: beide gebruiken hetzelfde referentietelsysteem op runtime-niveau.
Gezamenlijk gebruik van Objective-C en Swift in één project is gangbare praktijk voor legacy-projecten. Apple biedt Bridging Header — een automatisch gegenereerd bestand waarmee Swift Objective-C-klassen ziet en Objective-C Swift-klassen ziet die van NSObject overerven.
// ProjectName-Bridging-Header.h
// Swift ziet deze headers automatisch
#import "LegacyManager.h"
#import "NetworkClient.h"
#import "DataStore.h"Migratie van Objective-C naar Swift — een stapsgewijs proces. Nieuwe bestanden worden in Swift geschreven, oude worden geleidelijk gerefactord. Bridging Header wordt automatisch gegenereerd bij het toevoegen van het eerste Swift-bestand aan een Objective-C-project. Voor omgekeerde zichtbaarheid (ObjC → Swift) genereert Xcode het bestand
// Swift-klasse zichtbaar vanuit Objective-C
@objc class SwiftRouter: NSObject {
@objc func navigateToProfile(userId: Int) {
// implementatie
}
}Beperkingen: Swift value-types (struct, enum) zijn niet direct zichtbaar vanuit Objective-C — ze moeten worden ingepakt in class met @objc. Generics in Swift zijn beperkt toegankelijk vanuit Objective-C. Aanbevolen aanpak — schrijf nieuwe code in Swift en refactor bestaande Objective-C-code alleen bij wijziging van de betreffende functionaliteit.
Het belangrijkste voordeel van Objective-C boven Swift — volledige toegang tot runtime. Method swizzling, het vervangen van methode-implementaties tijdens uitvoering, maakt het mogelijk systeemmethoden te overschrijven zonder overerving. Bibliotheken zoals Aspects en JRSwizzle gebruiken deze mogelijkheid voor AOP (aspectgeoriënteerd programmeren) — monitoring, analyse en logging.
Forward invocation — nog een runtime-mogelijkheid: als een object niet reageert op een selector, roept het systeem forwardInvocation: aan, waardoor het bericht naar een ander object kan worden omgeleid. Dit is de basis van het Proxy-patroon in Objective-C (NSProxy), gebruikt voor uitgestelde initialisatie en gedistribueerde objecten.
Apple raadt aan om runtime-trucs in nieuwe code tot een minimum te beperken en de voorkeur te geven aan statische typering van Swift. In legacy-projecten is kennis van objc_msgSend, method_exchangeImplementations en objc_getAssociatedObject echter noodzakelijk voor het onderhouden van de bestaande codebase.
Objective-C ondersteunt property als syntactische suiker over ivar met getters/setters. De modifiers atomic/nonatomic, strong/weak/copy, readonly/readwrite en assign/retain bepalen het geheugengedrag en de draadveiligheid. Key-Value Observing (KVO) — een mechanisme voor het observeren van eigenschapswijzigingen, ingebouwd in de runtime: elk object kan zich abonneren op wijzigingen van eigenschappen van een ander object via addObserver.
Veelgestelde vragen
Een methodeaanroep ziet eruit als [object selector:argument]. Het bericht gaat door objc_msgSend, die de implementatie dynamisch vindt in de runtime. Een selector is de naam van de methode (@selector(methodName)), geen functieaanwijzer. Dit maakt swizzling en forward invocation mogelijk.
Category (@interface ClassName (Name)) voegt methoden toe aan elke klasse (inclusief systeemklassen) zonder overerving. Extension (@interface ClassName ()) wordt gedeclareerd in .m-bestand en kan property en ivar toevoegen. Category kan geen ivar toevoegen, extension wel.
Blocks — anonieme functies met syntaxis ^(parameters) { lichaam }, die variabelen uit de context vastleggen. Analoog aan lambda's in C++ en closures in Swift. Vereisen __weak om retain cycles te voorkomen bij het vastleggen van self. Gebruikt in UIKit, GCD en Foundation.
MRC — handmatige referentietelling: de programmeur roept retain, release, autorelease aan. ARC — automatisch: de compiler voegt retain/release in op basis van statische analyse. ARC is geen GC — objecten worden direct vrijgegeven bij het nulstellen van de teller. ARC ondersteunt __weak en __strong modifiers.
Ja, via Bridging Header. Swift ziet Objective-C via deze header, Objective-C ziet Swift via
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook