Podstawy Objective-C 2.0. Notatki programisty.

Wstęp

 

Historia

Język Objective-C pojawił się w 1986 roku, jako roszerzenie (nadzbiór) języka C. Wzorowany był na Smalltalk’u i rozszerza język C m.in. o mechanizmy obiektowości (wiki). Język ten jest głównie wykorzysytywany w Mac OS X oraz iOS.

Ta strona to moje notatki, w których postaram się zawrzeć najbardziej istotne cechy tego języka. Notatki dotyczą Objective-C 2.0 wprowadzonego w Mac OS X 10.5

Bardziej Java niż C++?

Objective-C przypomina poniekąd język Java bardziej niż C++, ponieważ kod wynikowy programu, generowany przez kompilator, wymaga specjalnego środowiska uruchomieniowego.

Czym Objective-C różni się od C i C++?

Objective-C wprowadza do języka C m.in.:

  • Symbol [] – służy do wywoływania metod,
  • Symbol @ – wykorzystuje się do definiowania struktur specyficznych dla Objective-C,
  • Nowe typy, jak np typ id. ( typ id jest wskaźnikiem do obiektu ),
  • Wszystie klasy niejawnie dziedziczą po klasie NSObject (podobnie jak w Javie),
  • Podobny składniowo do Smalltalka, z niego przejął też częściowo możliwości,
  • Dziedziczenie wyłącznie jednokrotne (klasa nie może dziedziczyć po więcej niż jednej klasie), lecz istnieje mechanizm @protocol, którego odpowiednikiem w Javie są interfejsy, dzięki czemu, de facto, klasa może być dzieckiem jednej klasy oraz dodatkowo implementować jakiś interfejs.
  • Obiekt niezainicjalizowany (pusty) jest reprezentowany przez słowo kluczowe nil.
  • Dynamiczna typizacja przy deklaracji obiektu, nie definiuje się stricte jego typu. Mówi się jedynie, że zmienna będzie reprezentowała obiekt. Decyzja jakiego typu to jest obiekt dokonuje się podczas pracy programu.

 

Podstawy

 

Typy danych

Typ danych/Grupa typówCharakterystyka
idWskaźnik na zmienne obiektowe dowolnego typu, dzięki wykorzystaniu mechanizmow dynamicznej typizacji.

id obiektDowolnejKlasy;
Klasa* obiektKlasyKlasa;

Zmienne nie wskazujące żadnego obiektu mają wartość nil (w Javie null).

BOOLW odróżnieniu od innych językow programowania, możliwe wartości dla zmiennej typu BOOL to YES i NO (a nie true i false).

BOOL success = NO;

W przypadku zastosowania frameworka Core Data, zmienna typu BOOL jest odwzorowana jako NSNumber w bazie danych.

UWAGA:
Typ BOOL jest zdefiniowany w pliku objc.h jako:

typedef signed char     BOOL;
#define YES             (BOOL)1
#define NO              (BOOL)0

W związku z tym nigdy nie powinniśmy robić czegoś takiego:

if (object.myBoolVar == YES) {
// a
} else {
// b
}

ponieważ kompilator nie poskarży się, jak object.myBoolVar. Wystarczy sobie wyobrazić, w który blok kodu wejdzie program, gdy wartość object.myBoolVar będzie równe 2. Dlatego zalecanym sposobem jest:

if (object.myBoolVar) {
// ...
}
 Typy ProsteTypy proste używane najczęściej jako składowe klas, zmienne używane w iteracjach, zmienne używane do różnego rodzaju obliczeń.Typ znakowy:

char l = '^';

Typy liczbowe:

int a = 12;
float b = 12.0f
double c = 12.0
 instancetypeJest to specjalny typ danych, możliwy do użycia jako typ wyniku zwracanego z metody w jakiejś klasie. Typ wyniku metody zdefiniowany słowem kluczowym instancetype powie kompilatorowi, że ta metoda zwraca instancję klasy, w której jest zdefiniowana ta metoda. Na przykład:

//TODO
@interface Telefon
+ (instancetype)telefonOdProducenta:(NSString*)producent;
@end;

Typ instancetype nie może być użyty w żadnym innym przypadku, a jedynie jako definicja typu zwracanego przez metodę. Jeśli interesuje Cię więcej szczegółów polecam ten artykuł i linki w nim zawarte.

 

Modyfikatory typów danych

Do typów prostych można zastosować pewne modyfikatory, zmieniające zakres wartości możliwych do zapisania do zmiennej tak zdefiniowanej. Poniższa tabelka prezentuje te elementy i ich przykładowe zastosowanie.

ModyfikatorCharakterystyka
long Zwiększa zakres typu liczbowego
short Zmniejsza zakres typu int do liczb od −32768 do +32767.
signedStosowany domyślnie. Wymusza tryb typu liczbowego ze znakiem. Dla 32 bitowego inta powoduje, że możliwy zakres zmienntej typu

signed int a;

to od −2 147 483 648 do +2 147 483 647

unsignedWymusza tryb bez znaku, dzięki czemu maksymalna liczba możliwa do zapisania w zmiennej z typem bez znaku jest 2 razy większa niż ze znakiem. Na przykład dla typu

unsigned int a;

jest to od 0 do 4 294 967 295.

Modyfikatory short/long mogą być użyte razem z signed/unsigned. Czyli możemy zapisać na przykład tak:

unsigned long int b;

Co da nam możliwość zapisania największej liczby typu int przewidzianej na danej platformie.

 

 

Deklaracja i definicja klas

 

Deklaracja

//definiujemy klase bazową wykorzystaną niżej w przykładzie
@interface Instrument {
  NSString* wlasciciel;
}
@end

 

//definiujemy interfejs klasy  Gitara, dziedziczącej po klasie Instrument
@interface Gitara : Instrument {
  NSString* rodzaj;
  //zmienna statyczna
  static NSString* drewno;
}
- (void) graj: (NSString *)Dzwiek;
- (void) ustawWlasciciela:(NSString *)owner iRodzaj: (NSString *)kind;
//metoda statyczna
+ (void) ustawDrewno:(NSString *)rodzajDrewna;
@end

Metody statyczne klasy rozpoczyna się od znaku “+” a pozostałe (niestatyczne) od znaku “-”.

Zwracam jeszcze raz szczególną uwagę to, że instrukcja @interface nie rozpoczyna deklaracji interfejsu w sensie takim jak np. w języku Java. Do tego służy instruckja @protocol. Tutaj (w Objective-C) odpowiada ono raczej słowu kluczowemu: class z języka Java.

Definicja

//import deklaracji interfejsu klasy
#import "Gitara.h"
 
//implementacja funkcjonalności
@implementation Gitara
 
//przykładowa metoda init
- (id) init {
  if ( self = [super init] ) {
    wlasciciel = @"Jan Kowalski";
  }
  return self;
}
 
//przykładowa metoda dealloc, służącej wyczyszczeniu pamięci z atrybutów klasy
- (void) dealloc {
    //zwolnienie pamieci atrybutów klasy
    [rodzaj release];
    //wywołanie metody dealloc na klasie bazowej
    [super dealloc];
}
 
//implementacja metody graj, która przyjmuje jeden argument: Dzwiek
- (void) graj: (NSString *)Dzwiek {
    //tutaj jakaś akcja
}
 
- (void) ustawWlasciciela:(NSString *)owner iRodzaj: (NSString *)kind {
    //przypisanie argumentów, do atrybutów klasy
 
    //dajemy znać środowisku, zeby przy najblizszej mozliwej okazji usunęło referencje w dogodnej dla niego chwili
    [rodzaj autorelease];
    //przypisujemy nową wartość dla rodzaju
    rodzaj = [kind retain];
 
    //podobnie dla właściciela
    [wlasciciel autorelease];
    wlasciciel = [owner retain];
}
 
+ (void) ustawDrewno:(NSString *)rodzajDrewna {
  drewno = [rodzajDrewna retain];
}
 
@end

Jeśli nasz plik z implementacją interfejsu klasy, zawiera odwołanie do jakiejś innej klasy, ale nie używa ani pól obiektów tej klasy, ani jej metod, to nie musimy używać dyrektywy

#import "MojaKlasa.h"

Zamiast niej lepiej użyć dyrektywy

@class MojaKlasa

Minimalizuje to kod widocznycz dla kompilatora, dając mu jednocześnie wystarczająco dużo informacji, że słowo

MojaKlasa

jest nazwą jakiejś klasy.

Operatory dostępu

Objective-C umożliwia definiowanie dostępu do zmiennych klasy na poziomach:

Operator dostępuOpis
@privateZmienna dostępna jedynie wewnątrz klasy, w ktorej została
zadeklarowana.
@protectedZmienna dostępna w klasie w ktorej została zadeklarowana oraz
w klasach potomnych. Brak dostępu pakietowego, jaki jest w Javie.
@publicZmienna dostępna dla każdego

 

Wysyłanie wiadomości do obiektu

//deklaracja obiektu i stworzenie instancji obiektu klasy gitara
id gitara = [[Gitara alloc] init];
 
//wysłanie wiadomości do obiektu gitara, aby wykonać metodę graj z parametrem "a"
[gitara graj: @"a"];
 
//wysłanie wiadomości do obiektu gitara, aby wykonać dwu argumentową metodę z parametrami: "Jan Kowalski" oraz "akustyczna"
[gitara ustawWlasciciela:@"Jan Kowalski" iRodzaj: @"akustyczna"];

Modyfikatory dostępu

Podobnie jak w języku Java, mamy do dyspozycji 4 poziomy widoczności atrybutów klasy.

ModyfikatorZasięg
@privateatrybut widoczny jedynie dla metod klasy, która go zadeklarowała
@protectedatrybut widoczny dla metod klasy, która go zadeklarowała, oraz dla jej klas potomnych
@publicatrybut widoczny „na zewnątrz” klasy
@packagezasięg pakietowy, widoczny w jednostce w której opisana jest implementacja klasy

Zarządzanie pamięcią

W języku Objective-C tak jak w języku C++ trzeba samemu zadbać, by zaalokowaną przez obiekty pamięć zwolnić. W wersji Objective-C 2.0 mamy dostępne 2 funkjconalności znane z Javy:

  • Zliczanie referencji
  • Garbage Collection
//deklaracja obiektu i stworzenie instancji obiektu klasy gitara
id gitara = [[Gitara alloc] init];
[gitara release];

 

Pamięć w Objective-C należy zwalniać (wywołać metodę release na obiekcie) wtedy, jeśli nasz kod wykonał jedną z operacji NARC na obiekcie. NARC to skrót od metod: New, Alloc, Retain, Copy. Proste. Zapamiętaj i używaj 🙂 Cała idea i pomysł na skrót opisane zostały w tym wpisie na StackOverflow.

 

ARC

W 2011 roku Apple wprowadziło ARC (Automatic Reference Counting) do standardu języka (oraz niezbędne zmiany do kompilatora). ARC jest wspierany od iOS 5 oraz Mac OS X Lion. ARC to tak naprawdę nowa jakość w Objective-C. Ale co to jest ten ARC? Kompilator (tak, już kompilator, a nie runtime) jest odpowiedzialny za zarządzanie pamięcią (rezerwację i zwalnianie). Podczas kompilacji kodu Objective-C kompilator wstawia odpowiednie instrukcje odpowiedzialne za zarządzanie pamięcią do wynikowego kodu maszynowego.

ARC nie zwalnia z myślenia. Ułatwia życie, ale nadal wymaga uwagi i świadomości tego co to jest ARC, jak działa i na czym bazuje. Zachęcam do zapoznania się z wpisem nt Retain Cycles, do których można z łatwością doprowadzić nieumiejętnym obchodzeniem się z zarządzaniem pamięcią.

Podsumowanie – najważniejsze proste konstrukcje językowe Objective-C

Kod w Objective-CWyjaśnienie działania
Kwadrat* kwadrat;
Deklaracja wskaźnika do obiektu klasy Kwadrat
id obiekt = [Klasa alloc];
Stworzenie nowej instancji klasy Klasa poprzez alokacje pamięci i inicjalizację jej składowych wartością 0 (zero)
id obiekt = [[Klasa alloc] init];
Stworzenie nowej instancji i inicjalizacja jej składowych poprzez wykonanie funkcji (id)init.
[obiekt metoda];
Wywołanie bezparametrowej metody “metoda” obiektu “obiekt”.
[kwadrat ustawWspolrzedne:20.0 :30.0];
Wywołanie metody “ustawWspolrzedne” przyjmującej 2 parametry, które są nienazwane, przez co metoda nie jest bardzo czytelna.
[prostokąt ustawSzerokosc:100 dlugosc:50];
Tutaj widzimy metodę, która została zadeklarowana jako “ ustawSzerokosc:dlugosc:”.
BOOL wolna;
wolna = [maszyna jestWolna];
Wywołanie metody zwracającej wartości typu BOOL z przypisaniem jej rezultatu do zmiennej.
[figura ustawKolor:[innaFigura pobierzKolor]];
Przykład zagnieżdżania wyrażeń.

2 przemyślenia nt. „Podstawy Objective-C 2.0. Notatki programisty.”

Odpowiedz na „MWLAnuluj pisanie odpowiedzi