ACROd tego miesiąca stałem się programistą Objective-C. Chociaż ten termin nie powinien sobie jeszcze przypisywać biorąc pod uwagę ,że obecnie uczę się składni języka oglądając programy Hello World. W najbliższym czasie na blogu będzie dużo wpisów o Objective-C. Tak czy siak, miałem oczywiście interesują konwersację z swoim współlokatorem oraz najlepszy przyjacielem na temat moich zdolności programistycznych.
Jeśli czytałeś ten wpis to wiesz ,że od czasu do czasu próbujemy sobie udowodnić kto z nas jest lepszy opowiadając sobie o tym co robimy w pracy. Biorąc pod uwagę ,że on pracuje w banku nie jest to łatwe zadanie.
Punkt rozmowy polegał na tym ,że ponieważ ja nie programowałem wcześniej w językach, w których trzeba zarządzać pamięcią własnoręcznie ( C , C++ ) to nauką języka Objective-C będzie ciężka.
No cóż z miło chęcią mogę powiedzieć ,że mój kolega się myli. Przynajmniej częściowo.
Otóż kompilator Objective-C oferuje mechanizm “Automatic Reference Counting” (ARC).
Mechanizm ten w dużym stopniu przekłada brzmienie i odpowiedzialność w zarządzaniu pamięci od programisty do automatu. ARC także usuwa potencjalne bugi, które mógłby się pojawić w wyniku wycieku pamięci.
Nie jest to mechanizm Garbage Collection pod inną nazwą. Po prostu proces dodania linijki kodu, która by oznaczyła obiektu do zwolnienia z pamięci został zautomatyzowany.
Gdy ARC jest włączone spokojnie możesz napisać taki kod bez żadnych obaw.
NSObject *obj = [[NSObject alloc] init];
// do some stuff
ARC automatycznie doda następującą linijkę kodu.
NSObject *obj = [[NSObject alloc] init];
// do some stuff
[obj release]; // **Added by ARC**
Oto diagram z dokumentacji Apple, który implikuje, że bez linijek zwalniających pamięć pianie kodu jest dużo szybsze.
Jest to na pewno prawda, zwłaszcza jeśli jesteś początkującym programistom Objective-C.
Gdy ARC jest włączone nie można nawet napisać swojego kodu zwalniającego pamięć.
Zasady działania ARC
Jestem początkującym programistą wiec szczerze mówiąc nie powinno mnie interesować jak programowanie wyglądało “przed” ,ale nie powiem mechanizm ARC wydawał mi się podejrzany. Musiałem więc sprawdzić dokładnie jak on działa. Zresztą przez mechanizm ARC programy z niektórych poradników odmawiają posłuszeństwa.
Oto co dzieje z kodem, gdy ARC jest włączone.
- Alloc i Init Obiektów
- Tworzenie obiektów działa tak samo ,ale nie można wywołać następujących funkcji (anyretain /release/autorelease/retainCount). Użycie selektorów niebezpośrednio też jest zakazane.
- Metody Dealloc
- Z reguły te metody zostaną utworzone za ciebie. Nie powinieneś wywoływać metod dealloc bezpośrednio. Możesz jednak utworzyć swoją metodę dealloc, która by zwalniała zasoby inne niż instancję zmiennych. Gdy więc wywołasz swojego dealloc nie używaj wywołania wyżej [super dealloc]. To zostanie zrobione za ciebie.
- Deklarowanie właściwości
- Przed ARC programista musiał powiedzieć kompilatorowi jak pamięć powinna być zarządzania używając specjalnych dyrektyw (theassign, retain, copy). Te parametry nie są używane w ARC. Zamiast tego mamy silne i słabe parametry, które mówią kompilatorowi jak powinien traktować te właściwości.
- Wskaźniki do struktur C
- Dokumentacja silnie wskazuje na używanie klas zamiast struktur. Ma to sens, ponieważ ACR struktur by nie obsłużył. Jeśli migrujesz swój kod do wersji ACR prawdopodobnie dostaniesz małego bólu głowy z tego powodu.
- ARC jednak może być wybiorczo wyłączone dla pojedynczego pliku,
- Dokumentacja silnie wskazuje na używanie klas zamiast struktur. Ma to sens, ponieważ ACR struktur by nie obsłużył. Jeśli migrujesz swój kod do wersji ACR prawdopodobnie dostaniesz małego bólu głowy z tego powodu.
- Rzutowanie pomiędzy id i void
- Woo dosyć zaawansowany tematy. Rzutowanie te odbywa się, gdy obiekty z biblioteki C gadają z bibliotekami Objective-C. Jest to znane pod nazwą Toll Free Bridging.
- Mając włączony ARC musisz dać kompilatorowi pewne wskazów kiedy obiekty z biblioteki Core Foundation języka C znajdują się poza kontrolą ARC i sam je obsłużyć.
- Osobiście nie mam pojęcia o czym teraz piszę xD ,ale dużo można dowiedzieć się z Internetu.
- Woo dosyć zaawansowany tematy. Rzutowanie te odbywa się, gdy obiekty z biblioteki C gadają z bibliotekami Objective-C. Jest to znane pod nazwą Toll Free Bridging.
- Przy użyciu ARC pojawia się nowa dyrektywa “@autorelasepool”, która zastępuję NSAutoReleasePool.
- Inna ciekawostka. Klasy operujące na pamięci “Zone based” nie istnieją już w SDK. Nie możesz więc użyć obiektów NSAllocateObject i NSDeallocateObject
Deklarowanie właściwości z ARC
Okej więc jak deklarujemy właściwości w nowoczesny programowaniu Objective-C.
Oto jak wygląda podział na silną i słabą referencję.
Silna referencja
Silna referencja jest to referencja (duh) do obiektu, który zatrzymuje się przed operacją zwalniania (deallocated) z powodu swojego właściciela. Mówiąc proście ma on związek ze swoim właścicielem . Wcześniej kod by wyglądał tak.
// Non-ARC Compliant Declaration
@property(retain) NSObject *obj;
ARC zrobi mniej więcej to samo, gdy użyjemy poniższej składni.
// ARC Compliant Declaration
@property(strong) NSObject *obj;
Wtedy ARC zadba oto aby instancja ten klasy dzieliła swoje życie z referowanym obiektem. (Nie będzie mogła być zwolniona (deallocated) przed swoim właścicielem).
Słabe referencje
Słabe referencje działają odwrotnie. Jeśli obiekt dziecko nie dzielić odpowiedzialności z obiektem rodzica wtedy powinniśmy użyć słabej referencji.
// ARC Compliant Declaration
@property(weak) NSObject *parentObj;
Kwalifikatory dla regularnych zmiennych
Dla regularnych zmiennych mamy następujące dyrektywy.
__strong
__weak
__unsafe_unretained
__autoreleasing
Te dyrektywy nie są często używane. Możesz się jednak z nimi spotkać w trakcie migracji kodu. Z reguły korzystamy z dyrektyw “weak” i “strong”.
- ___strong: jest to domyślny zapis i nie musi być on deklarowany. To oznacza ,że życie utworzonego obiektu jest zależne od obecnego zakresu kodu.
- “Obecny zakres kodu” referuje się do nawiasów klamrowych, w których opisujemy działanie metod, pętl bloków if i itp.
- ___weak: oznacza ,że obiekt może być zniszczony w każdym momencie. Jest to użyteczne tylko wtedy gdy obiekt ma już silną referencje gdzieś indziej. Gdy zmienna zostanie zniszczona jest ona ustawiona na nil (czyli null).
- ___unsafe_unretained : działa podobnie jak ___weak ,ale jego wskaźnik nie jest ustawiony na nil, gdy obiekt jest zwolniony (deallocated).
- ___autoreleasing: Jest on używany, gdy chcemy przesłać obiekt jako referencje. Przykładem jest obiekt NSError.
ARC jest super
ACR na pewno jest wspaniałą rzeczą, gdyż jako oficjalny programista WEBOWY nie mam dużego pojęcia na temat zarządzania pamięci w językach nisko poziomowych.
Z drugie strony miałem pewną obawę i musiałem się upewnić jak ARC dokładnie działa.
Był to dobry pomysł, ponieważ teraz wie ,że większość poradników, jak i książka, którą kupiłem do nauki Objective-C posiadają nieaktualne informację.
Programy hello world opisane krok po kroku nie działają ,ze względu na ARC.
Dla zaawansowane programisty Objective-C zapewne w głowie rodzi się pytanie czy samodzielne zarządzanie działa lepiej niż automatyczne. Niestety ,ale zwycięstwo stoi po stronie automatu. Jednak jak każdy automat nie działa on w bardzo zaawansowany przypadkach np. Toll Free Bridging. .