Objective-C — dinamikus üzenettovábbítással rendelkező programozási nyelv, amelyet Brad Cox alkotott az 1980-as években. Az Apple az Objective-C-t választotta fő nyelvként a NeXTSTEP-hez, majd később az iOS SDK-hoz. Programming With Objective-C — bevezetés az üzenetszintaxisba és a memóriakezelésbe.
Főbb pontok
Objective-C — programozási nyelv, amely a C-t Smalltalk-stílusú objektumorientált programozási képességekkel bővíti. Az Objective-C kód LLVM-en vagy GCC-n keresztül natív gépi kóddá fordul, megtartva a teljes visszafelé kompatibilitást C-vel — bármely C kód helyes Objective-C-ben.
Az Apple 1997-ben felvásárolta a NeXT-et (az Objective-C-vel együtt). A nyelv a Cocoa és Cocoa Touch — a macOS és iOS keretrendszereinek alapjává vált. 2014 óta az Apple a Swift-et népszerűsíti helyettesítőként, de az Objective-C továbbra is kritikus fontosságú a legacy projektek és egyes rendszerkeretrendszerek számára. Az Apple szerint (WWDC 2024) az App Store alkalmazásainak körülbelül 35%-a még mindig tartalmaz Objective-C kódot.
Kulcsjellemző — dinamikus futásidejű környezet. Ellentétben a Swift-tel, ahol a metódushívások fordítási időben oldódnak meg, az Objective-C futásidőben küld üzeneteket az objc_msgSend függvényen keresztül. Ez lehetővé teszi a metódusok menet közbeni felülírását (method swizzling), osztályok dinamikus hozzáadását és a forward invocation használatát nem létező szelektorokhoz.
Bármely C kód helyes Objective-C-ben. Az objektumréteg osztályokat (@interface/@implementation), kategóriákat, protokollokat (@protocol) és dinamikus típusozást (id) ad hozzá. A fájlok .m (implementáció) és .h (fejlécek) kiterjesztéssel rendelkeznek.
Üzenetszintaxis — az Objective-C fő különbsége a C-szerű nyelvektől. Az object.method(argument) helyett [object method:argument] használatos. Minden üzenet áthalad az objc_msgSend-en, amely dinamikusan keresi a metódus implementációját a futásidejű környezetben.
// Üzenetszintaxis névvel ellátott paraméterekkel
NSString *greeting = [NSString stringWithFormat:@"Hello, %@", name];
// Beágyazott üzenetek
NSArray *sortedArray = [[array sortedArrayUsingSelector:@selector(compare:)] copy];
// Típusellenőrzés introspekcióval
if ([object isKindOfClass:[UIView class]]) {
UIView *view = (UIView *)object;
view.backgroundColor = [UIColor redColor];
}Dynamic dispatch lehetővé teszi a metódusok futásidejű felülírását (method swizzling) — egy hatékony, de veszélyes technika. Például az olyan keretrendszerek, mint az AFNetworking és az Aspects, swizzling-et használnak az URLSession-hívások elfogására. Az Apple figyelmeztet: a swizzling megzavarhatja a rendszerkeretrendszerek működését, ha helytelenül használják.
Categories — az Objective-C egyedülálló képessége, hogy metódusokat adjon meglévő osztályokhoz (beleértve a rendszerosztályokat, mint az NSString és UIView) öröklődés és forráskód-hozzáférés nélkül. A kategóriák a @interface ClassName (CategoryName) segítségével deklarálhatók.
// UIColor+Hex.h fájl — kategória a UIColor számára
@interface UIColor (Hex)
+ (instancetype)colorWithHex:NSUIntegerhex;
@end
// UIColor+Hex.m fájl — implementáció
@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) — a kategória egy speciális típusa, amely .m fájlban név nélkül van deklarálva: @interface ClassName (). A kategóriákkal ellentétben az extensions nem csak metódusokat, hanem ivar (példányváltozókat) és property-t is hozzáadhat. Az extensions a belső API külső modulok elől való elrejtésére szolgál.
Blocks — névtelen függvények az Objective-C-ben, amelyek változókat rögzítenek a külső láthatósági tartományból. A blokkok szintaxisa: ^(int x) { return x * 2; }. A Blocks a UIKit-ben callback-kezelőkhöz, a Grand Central Dispatch-ben aszinkron feladatokhoz, valamint az NSArray/NSDictionary gyűjteményekben funkcionális műveletekhez használatos.
// Blokk típusának deklarálása
typedef void (^CompletionBlock)(BOOL success, NSError *error);
// Blokk paraméterként
- (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);
}
});
}Memóriakezelés a blokkokban kritikus fontosságú. A blokok erős referenciával rögzítik a self-et, ami retain cycle-t hoz létre közvetlen használat esetén. Megoldás — __weak typeof(self) weakSelf = self, utólagos ellenőrzéssel a blokkon belül. Ez a probléma a Swift-ben teljes mértékben megoldódott a capture listák [weak self] segítségével.
Az Objective-C az MRC (Manual Reference Counting)-től az ARC (Automatic Reference Counting)-ig vezető utat járta be. Az MRC-ben a programozó manuálisan hívta a retain-t (számláló növelése), release-t (csökkentés) és autorelease-t (késleltetett felszabadítás). A hibák ezekben a hívásokban memóriaszivárgáshoz vagy összeomlásokhoz vezettek a dangling pointers miatt.
| Művelet | MRC | ARC |
|---|---|---|
| Objektum létrehozása | [[Object alloc] init] | [[Object alloc] init] |
| Referencia megtartása | [object retain] | Automatikus |
| Felszabadítás | [object release] | Automatikus |
| Automatikus felszabadítás | [object autorelease] | Automatikus (nem szükséges) |
| Weak referencia | __weak nem létezett | __weak (automatikus nil) |
Az ARC az Xcode 4.2-ben és az LLVM 3.0-ban (2011) került bevezetésre. A fordító automatikusan beszúrja a retain/release-t a fordítás során, elemezve az objektumok élettartamát. Az ARC nem szemétgyűjtés (garbage collection) — ez statikus elemzés automatikus beszúrásokkal. Az Objective-C ARC kompatibilis a Swift ARC-val: mindkettő ugyanazt a referenciaszámlálási rendszert használja futásidejű szinten.
Az Objective-C és Swift együttes használata egy projekten belül — általános gyakorlat a legacy projekteknél. Az Apple Bridging Header-t biztosít — egy automatikusan generált fájlt, amelyen keresztül a Swift látja az Objective-C osztályokat, az Objective-C pedig a NSObject-ből öröklődő Swift osztályokat.
// ProjectName-Bridging-Header.h
// A Swift ezeket a fejléceket automatikusan látja
#import "LegacyManager.h"
#import "NetworkClient.h"
#import "DataStore.h"Migráció Objective-C-ről Swift-re — szakaszos folyamat. Az új fájlok Swift-ben íródnak, a régiek fokozatosan refaktorálásra kerülnek. A Bridging Header automatikusan generálódik az első Swift fájl Objective-C projekthez adásakor. A fordított láthatósághoz (ObjC → Swift) az Xcode létrehozza a
// Objective-C-ből látható Swift osztály
@objc class SwiftRouter: NSObject {
@objc func navigateToProfile(userId: Int) {
// implementáció
}
}Korlátozások: a Swift értéktípusok (struct, enum) nem láthatók közvetlenül Objective-C-ből — class-ba kell csomagolni őket @objc-val. A Swift-ben lévő Generics korlátozottan érhető el Objective-C-ből. Ajánlott megközelítés — új kódot Swift-ben írni, a meglévő Objective-C kódot pedig csak a megfelelő funkcionalitás változásakor refaktorálni.
Az Objective-C fő előnye a Swift-tel szemben — teljes hozzáférés a futásidejű környezethez. A method swizzling, a metódusimplementációk futásidőbeni cseréje, lehetővé teszi a rendszermetódusok felülírását öröklődés nélkül. Az olyan könyvtárak, mint az Aspects és a JRSwizzle, ezt a képességet használják AOP-hoz (aspektusorientált programozás) — monitorozáshoz, analitikához és naplózáshoz.
Forward invocation — egy másik futásidejű képesség: ha egy objektum nem válaszol egy szelektorra, a rendszer meghívja a forwardInvocation:-t, lehetővé téve az üzenet átirányítását egy másik objektumhoz. Ez a Proxy minta alapja az Objective-C-ben (NSProxy), amelyet késleltetett inicializáláshoz és elosztott objektumokhoz használnak.
Az Apple azt javasolja, hogy minimalizáljuk a futásidejű trükkök használatát az új kódban, előnyben részesítve a Swift statikus típusozását. Azonban a legacy projektekben az objc_msgSend, method_exchangeImplementations és objc_getAssociatedObject ismerete elengedhetetlen a meglévő kódbázis karbantartásához.
Az Objective-C támogatja a property-t szintaktikai cukorként az ivar felett getterekkel/setterekkel. Az atomic/nonatomic, strong/weak/copy, readonly/readwrite és assign/retain módosítók határozzák meg a memória-viselkedést és a szálbiztonságot. A Key-Value Observing (KVO) — a tulajdonságváltozások megfigyelésének mechanizmusa, amely beépítve van a futásidejű környezetbe: bármely objektum feliratkozhat egy másik objektum tulajdonságváltozásaira az addObserver segítségével.
Gyakran ismételt kérdések
A metódushívás így néz ki: [object selector:argument]. Az üzenet áthalad az objc_msgSend-en, amely dinamikusan megtalálja az implementációt a futásidejű környezetben. A szelektor a metódus neve (@selector(methodName)), nem függvénymutató. Ez lehetővé teszi a swizzling-et és a forward invocation-t.
A Category (@interface ClassName (Name)) metódusokat ad bármely osztályhoz (beleértve a rendszerosztályokat) öröklődés nélkül. Az Extension (@interface ClassName ()) .m fájlban van deklarálva, és hozzáadhat property-t és ivar-t. A Category nem adhat hozzá ivar-t, az Extension igen.
A Blocks — névtelen függvények ^(paraméterek) { törzs } szintaxissal, amelyek változókat rögzítenek a kontextusból. A C++ lambda-inak és a Swift closures-ének megfelelői. __weak szükséges a retain cycles megelőzéséhez a self rögzítésekor. Használatosak UIKit-ben, GCD-ben és Foundation-ben.
MRC — kézi referenciaszámlálás: a programozó retain, release, autorelease hívásokat végez. ARC — automatikus: a fordító retain/release-t szúr be statikus elemzés alapján. Az ARC nem GC — az objektumok azonnal felszabadulnak a számláló nullázásakor. Az ARC támogatja a __weak és __strong módosítókat.
Igen, a Bridging Header segítségével. A Swift ezen a fejlécen keresztül látja az Objective-C-t, az Objective-C pedig a
Összefoglaló
Kulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is