Objective-C — програмски језик са динамичким слањем порука, створен од Бреда Кокса 1980-их. Apple је изабрао Objective-C као главни језик за NeXTSTEP, а затим и за iOS SDK. Programming With Objective-C — увод у синтаксу порука и управљање меморијом.
Главно
Objective-C — програмски језик који проширује C могућностима објектно-оријентисаног програмирања у стилу Smalltalk-а. Код на Objective-C-у се компилира кроз LLVM или GCC у нативни машински код, чувајући потпуну уназад компатибилност са C-ом — било који C код је исправан у Objective-C-у.
Apple је преузео NeXT (заједно са Objective-C-ом) 1997. године. Језик је постао основа Cocoa и Cocoa Touch — оквира за macOS и iOS. Од 2014. Apple промовише Swift као замену, али Objective-C остаје критично важан за легаси пројекте и неке системске оквире. Према Apple-у (WWDC 2024), око 35% апликација у App Store-у још увек садржи Objective-C код.
Кључна карактеристика — динамички runtime. За разлику од Swift-а, где се позиви метода решавају у фази компилације, Objective-C шаље поруке током извршавања кроз функцију objc_msgSend. То омогућава преиначавање метода у лету (method swizzling), динамичко додавање класа и коришћење forward invocation-а за непостојеће селекторе.
Било који C код је исправан у Objective-C-у. Објектна надградња додаје класе (@interface/@implementation), категорије, протоколе (@protocol) и динамичко типизовање (id). Датотеке имају екстензије .m (имплементација) и .h (заглавља).
Синтакса порука — главна разлика Objective-C-а од C-сличних језика. Уместо object.method(argument) користи се [object method:argument]. Свака порука пролази кроз objc_msgSend, који динамички тражи имплементацију метода у runtime-у.
// Синтакса порука са именованим параметрима
NSString *greeting = [NSString stringWithFormat:@"Hello, %@", name];
// Угњеждене поруке
NSArray *sortedArray = [[array sortedArrayUsingSelector:@selector(compare:)] copy];
// Провера типа кроз интроспекцију
if ([object isKindOfClass:[UIView class]]) {
UIView *view = (UIView *)object;
view.backgroundColor = [UIColor redColor];
}Dynamic dispatch омогућава преиначавање метода у runtime-у (method swizzling) — моћна, али опасна техника. На пример, оквири попут AFNetworking-а и Aspects-а користе swizzling за пресретање позива URLSession-а. Apple упозорава: swizzling може пореметити рад системских оквира ако се неправилно користи.
Categories — јединствена могућност Objective-C-а да додаје методе постојећим класама (укључујући системске, попут NSString и UIView) без наслеђивања и без приступа изворном коду. Категорије се декларишу кроз @interface ClassName (CategoryName).
// Датотека UIColor+Hex.h — категорија за UIColor
@interface UIColor (Hex)
+ (instancetype)colorWithHex:NSUIntegerhex;
@end
// Датотека UIColor+Hex.m — имплементација
@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) — посебна врста категорије, декларисана у .m датотеци без имена: @interface ClassName (). За разлику од категорија, extensions могу додавати не само методе, већ и ivar (инстанцне варијабле) и property. Extensions се користе за скривање унутрашњег API-ја од спољашњих модула.
Blocks — анонимне функције у Objective-C-у, које хватају променљиве из спољашњег опсега видљивости. Синтакса блокова: ^(int x) { return x * 2; }. Blocks се користе у UIKit-у за callback-обраднике, у Grand Central Dispatch-у за асинхроне задатке и у колекцијама NSArray/NSDictionary за функционалне операције.
// Декларација типа блока
typedef void (^CompletionBlock)(BOOL success, NSError *error);
// Блок као параметар
- (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);
}
});
}Управљање меморијом у блоковима је критично. Блокови хватају self јаком референцом, што ствара retain cycle при директном коришћењу. Решење — __weak typeof(self) weakSelf = self, са накнадном провером унутар блока. Овај проблем је потпуно решен у Swift-у кроз листе за хватање [weak self].
Objective-C је прешао пут од MRC (Manual Reference Counting) до ARC (Automatic Reference Counting). У MRC-у програмер је ручно позивао retain (повећање бројача), release (смањење) и autorelease (одложени release). Грешке у овим позивима доводиле су до цурења меморије или падова због dangling pointers-а.
| Операција | MRC | ARC |
|---|---|---|
| Креирање објекта | [[Object alloc] init] | [[Object alloc] init] |
| Држање референце | [object retain] | Аутоматски |
| Ослобађање | [object release] | Аутоматски |
| Аутоослобађање | [object autorelease] | Аутоматски (није потребно) |
| Weak референца | __weak није постојао | __weak (аутоматски nil) |
ARC је представљен у Xcode 4.2 и LLVM 3.0 (2011). Компилатор аутоматски убацује retain/release у фази компилације, анализирајући животни век објеката. ARC није сакупљање смећа (garbage collection) — то је статичка анализа са аутоматским убацивањем. Objective-C ARC је компатибилан са Swift ARC: оба користе исти систем бројања референци на нивоу runtime-а.
Заједничко коришћење Objective-C и Swift-а у једном пројекту — уобичајена пракса за легаси пројекте. Apple обезбеђује Bridging Header — аутоматски генерисану датотеку кроз коју Swift види Objective-C класе, а Objective-C види Swift класе наслеђене од NSObject-а.
// ProjectName-Bridging-Header.h
// Swift види ова заглавља аутоматски
#import "LegacyManager.h"
#import "NetworkClient.h"
#import "DataStore.h"Миграција са Objective-C на Swift — фазни процес. Нове датотеке се пишу у Swift-у, старе се постепено рефакторишу. Bridging Header се аутоматски генерише при додавању прве Swift датотеке у Objective-C пројекат. За обрнуту видљивост (ObjC → Swift), Xcode генерише датотеку
// Swift класа видљива из Objective-C-а
@objc class SwiftRouter: NSObject {
@objc func navigateToProfile(userId: Int) {
// имплементација
}
}Ограничења: Swift value-типови (struct, enum) нису видљиви из Objective-C-а директно — морају се умотати у class са @objc. Generics у Swift-у су ограничено доступни из Objective-C-а. Препоручени приступ — пишите нови код у Swift-у, а постојећи Objective-C код рефакторишите само при промени одговарајуће функционалности.
Главна предност Objective-C-а над Swift-ом — пун приступ runtime-у. Method swizzling, замена имплементације метода током извршавања, омогућава преиначавање системских метода без наслеђивања. Библиотеке попут Aspects-а и JRSwizzle-а користе ову могућност за AOP (аспектно-оријентисано програмирање) — праћење, аналитику и логирање.
Forward invocation — још једна runtime могућност: ако објекат не одговара на селектор, систем позива forwardInvocation:, омогућавајући преусмеравање поруке другом објекту. То је основа Proxy узорка у Objective-C-у (NSProxy), који се користи за одложену иницијализацију и дистрибуиране објекте.
Apple препоручује минимизирање коришћења runtime трикова у новом коду, дајући предност статичком типизовању Swift-а. Међутим, у легаси пројектима познавање objc_msgSend, method_exchangeImplementations и objc_getAssociatedObject је неопходно за одржавање постојеће базе кода.
Objective-C подржава property као синтаксни шећер над ivar-ом са getter-има/setter-има. Модификатори atomic/nonatomic, strong/weak/copy, readonly/readwrite и assign/retain одређују понашање меморије и безбедност нити. Key-Value Observing (KVO) — механизам посматрања промена својстава уграђен у runtime: било који објекат може да се претплати на промене својстава другог објекта кроз addObserver.
Често постављана питања
Позив методе изгледа као [object selector:argument]. Порука пролази кроз objc_msgSend, који динамички проналази имплементацију у runtime-у. Селектор је име методе (@selector(methodName)), а не показивач на функцију. То омогућава swizzling и forward invocation.
Category (@interface ClassName (Name)) додаје метода било којој класи (укључујући системске) без наслеђивања. Extension (@interface ClassName ()) се декларише у .m датотеци и може додавати property и ivar. Category не може додавати ivar, extension — може.
Blocks — анонимне функције са синтаксом ^(параметри) { тело }, које хватају променљиве из контекста. Аналогно ламбдама у C++ и closures-има у Swift-у. Захтевају __weak за спречавање retain cycles-а при хватању self-а. Користе се у UIKit-у, GCD-у и Foundation-у.
MRC — ручно бројање референци: програмер позива retain, release, autorelease. ARC — аутоматско: компилатор убацује retain/release на основу статичке анализе. ARC није GC — објекти се ослобађају одмах при нулирању бројача. ARC подржава __weak и __strong модификаторе.
Да, кроз Bridging Header. Swift види Objective-C кроз ово заглавље, Objective-C види Swift кроз
Закључци
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође