Objective-C — un limbaj de programare cu expediere dinamică de mesaje, creat de Brad Cox în anii 1980. Apple a ales Objective-C ca limbaj principal pentru NeXTSTEP, iar apoi pentru iOS SDK. Programming With Objective-C — introducere în sintaxa mesajelor și gestionarea memoriei.
Principalele
Objective-C — un limbaj de programare care extinde C cu capacități de programare orientată pe obiecte în stil Smalltalk. Codul Objective-C se compilează prin LLVM sau GCC în cod mașină nativ, păstrând compatibilitatea completă inversă cu C — orice cod C este corect în Objective-C.
Apple a achiziționat NeXT (împreună cu Objective-C) în 1997. Limbajul a devenit baza Cocoa și Cocoa Touch — framework-urile pentru macOS și iOS. Din 2014, Apple promovează Swift ca înlocuitor, dar Objective-C rămâne critic pentru proiectele legacy și unele framework-uri de sistem. Potrivit Apple (WWDC 2024), aproximativ 35% din aplicațiile din App Store conțin încă cod Objective-C.
Caracteristica cheie — runtime dinamic. Spre deosebire de Swift, unde apelurile de metode se rezolvă la compilare, Objective-C trimite mesaje în timpul execuției prin funcția objc_msgSend. Aceasta permite suprascrierea metodelor din zbor (method swizzling), adăugarea dinamică a claselor și utilizarea forward invocation pentru selectori inexistenți.
Orice cod C este corect în Objective-C. Suprastructura orientată pe obiecte adaugă clase (@interface/@implementation), categorii, protocoale (@protocol) și tipizare dinamică (id). Fișierele au extensiile .m (implementare) și .h (antete).
Sintaxa mesajelor — principala diferență a Objective-C față de limbile de tip C. În loc de object.method(argument) se folosește [object method:argument]. Fiecare mesaj trece prin objc_msgSend, care caută dinamic implementarea metodei în runtime.
// Sintaxa mesajelor cu parametri numiți
NSString *greeting = [NSString stringWithFormat:@"Hello, %@", name];
// Mesaje imbricate
NSArray *sortedArray = [[array sortedArrayUsingSelector:@selector(compare:)] copy];
// Verificarea tipului prin instrospecție
if ([object isKindOfClass:[UIView class]]) {
UIView *view = (UIView *)object;
view.backgroundColor = [UIColor redColor];
}Dynamic dispatch permite suprascrierea metodelor în runtime (method swizzling) — o tehnică puternică, dar periculoasă. De exemplu, framework-uri precum AFNetworking și Aspects folosesc swizzling pentru interceptarea apelurilor URLSession. Apple avertizează: swizzling poate perturba funcționarea framework-urilor de sistem dacă este folosit incorect.
Categories — o capacitate unică a Objective-C de a adăuga metode la clase existente (inclusiv sistemice, precum NSString și UIView) fără moștenire și fără acces la codul sursă. Categoriile se declară prin @interface ClassName (CategoryName).
// Fișierul UIColor+Hex.h — categorie pentru UIColor
@interface UIColor (Hex)
+ (instancetype)colorWithHex:NSUIntegerhex;
@end
// Fișierul UIColor+Hex.m — implementare
@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) — un tip special de categorie, declarat în fișierul .m fără nume: @interface ClassName (). Spre deosebire de categorii, extensions pot adăuga nu doar metode, ci și ivar (variabile de instanță) și property. Extensions sunt folosite pentru ascunderea API-ului intern de modulele externe.
Blocks — funcții anonime în Objective-C, care capturează variabile din domeniul de vizibilitate extern. Sintaxa blocurilor: ^(int x) { return x * 2; }. Blocks sunt folosite în UIKit pentru handler-e de callback, în Grand Central Dispatch pentru sarcini asincrone și în colecțiile NSArray/NSDictionary pentru operații funcționale.
// Declararea tipului de bloc
typedef void (^CompletionBlock)(BOOL success, NSError *error);
// Bloc ca parametru
- (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);
}
});
}Gestionarea memoriei în blocuri este critică. Blocurile capturează self cu referință puternică, ceea ce creează retain cycle la utilizarea directă. Soluția — __weak typeof(self) weakSelf = self, cu verificare ulterioară în interiorul blocului. Această problemă este complet rezolvată în Swift prin listele de capturare [weak self].
Objective-C a parcurs drumul de la MRC (Manual Reference Counting) la ARC (Automatic Reference Counting). În MRC, programatorul apela manual retain (creșterea contorului), release (scăderea) și autorelease (release întârziat). Erorile în aceste apeluri duceau la scurgeri de memorie sau crash-uri din cauza dangling pointers.
| Operațiune | MRC | ARC |
|---|---|---|
| Crearea obiectului | [[Object alloc] init] | [[Object alloc] init] |
| Păstrarea referinței | [object retain] | Automat |
| Eliberarea | [object release] | Automat |
| Autoeliberarea | [object autorelease] | Automat (nu este necesar) |
| Referința Weak | __weak nu exista | __weak (nil automat) |
ARC a fost introdus în Xcode 4.2 și LLVM 3.0 (2011). Compilatorul inserează automat retain/release la compilare, analizând durata de viață a obiectelor. ARC nu este garbage collection — este analiză statică cu inserții automate. Objective-C ARC este compatibil cu Swift ARC: ambele folosesc același sistem de numărare a referințelor la nivel de runtime.
Utilizarea comună a Objective-C și Swift într-un singur proiect — o practică obișnuită pentru proiectele legacy. Apple oferă Bridging Header — un fișier generat automat prin care Swift vede clasele Objective-C, iar Objective-C vede clasele Swift moștenite de la NSObject.
// ProjectName-Bridging-Header.h
// Swift vede aceste antete automat
#import "LegacyManager.h"
#import "NetworkClient.h"
#import "DataStore.h"Migrarea de la Objective-C la Swift — un proces etapizat. Fișierele noi se scriu în Swift, cele vechi se refactorizează treptat. Bridging Header se generează automat la adăugarea primului fișier Swift într-un proiect Objective-C. Pentru vizibilitatea inversă (ObjC → Swift), Xcode generează fișierul
// Clasă Swift vizibilă din Objective-C
@objc class SwiftRouter: NSObject {
@objc func navigateToProfile(userId: Int) {
// implementare
}
}Limitări: tipurile value Swift (struct, enum) nu sunt vizibile direct din Objective-C — trebuie împachetate în class cu @objc. Generics în Swift sunt limitat accesibile din Objective-C. Abordarea recomandată — scrieți cod nou în Swift, iar codul Objective-C existent refactorizați-l doar la modificarea funcționalității respective.
Principalul avantaj al Objective-C față de Swift — acces complet la runtime. Method swizzling, înlocuirea implementării metodelor în timpul execuției, permite suprascrierea metodelor de sistem fără moștenire. Bibliotecile precum Aspects și JRSwizzle folosesc această capacitate pentru AOP (programare orientată pe aspecte) — monitorizare, analitică și logare.
Forward invocation — o altă capacitate runtime: dacă un obiect nu răspunde la selector, sistemul apelează forwardInvocation:, permițând redirecționarea mesajului către alt obiect. Aceasta stă la baza pattern-ului Proxy în Objective-C (NSProxy), utilizat pentru inițializare întârziată și obiecte distribuite.
Apple recomandă minimizarea utilizării trucurilor runtime în codul nou, preferând tipizarea statică a Swift. Totuși, în proiectele legacy, cunoașterea objc_msgSend, method_exchangeImplementations și objc_getAssociatedObject este necesară pentru întreținerea bazei de cod existente.
Objective-C suportă property ca zahăr sintactic peste ivar cu gettere/settere. Modificatorii atomic/nonatomic, strong/weak/copy, readonly/readwrite și assign/retain determină comportamentul memoriei și siguranța firelor de execuție. Key-Value Observing (KVO) — mecanism de observare a modificărilor proprietăților încorporat în runtime: orice obiect se poate abona la modificările proprietăților altui obiect prin addObserver.
Întrebări frecvente
Apelarea metodei arată ca [object selector:argument]. Mesajul trece prin objc_msgSend, care găsește dinamic implementarea în runtime. Selectorul este numele metodei (@selector(methodName)), nu un pointer către funcție. Aceasta permite swizzling și forward invocation.
Category (@interface ClassName (Name)) adaugă metode la orice clasă (inclusiv sistemice) fără moștenire. Extension (@interface ClassName ()) se declară în fișierul .m și poate adăuga property și ivar. Category nu poate adăuga ivar, extension — poate.
Blocks — funcții anonime cu sintaxa ^(parametri) { corp }, care capturează variabile din context. Analogul lambda în C++ și closures în Swift. Necesită __weak pentru prevenirea retain cycles la capturarea self. Folosite în UIKit, GCD și Foundation.
MRC — numărarea manuală a referințelor: programatorul apelează retain, release, autorelease. ARC — automată: compilatorul inserează retain/release pe baza analizei statice. ARC nu este GC — obiectele se eliberează imediat la zeroirea contorului. ARC suportă modificatorii __weak și __strong.
Da, prin Bridging Header. Swift vede Objective-C prin acest antet, Objective-C vede Swift prin
Concluzii
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și