Wstęp

W drugiej części małego tutoriala postaram się opisać podstawy języka Objective-C, który jest głównym środowiskiem programowania na iPhonie. Apple wspierał wcześniej SDK dla Javy jednak zaprzestał na rzecz własnego języka. Nie jest to pewnie zaskoczenie, że forsują swoje rozwiązanie;)

Objective-C jest rozszerzeniem języka ANSI C o możliwości programowania obiektowego. Zatem dostajemy dziedziczenie, enkapsulacje czy polimorfizm. Symbole [] oraz @ są podstawą rozszerzenia Objective-C. Zmian jest trochę więcej ale o nich poniżej.

Składnia

ID

Ważnym nowym składnikiem jest id, który jest uniwersalną referencją (patrząc od strony C jest to wskaźnik) do każdego obiektu. Z tym, że referencja obiektu nil ma wartość 0.

Klasy

Klasy definiujemy w plikach o rozszerzeniu *.h natomiast implementacje klasy dokonujemy w plikach o rozszerzeniu *.m lub *.mm dla C++. W pliku *.h definiujemy zmienne oraz metody klasy. Poniżej składnia deklaracji klasy Motorower dziedzicząca po podstawowej klasie NSObject.

#import "file.h"

@interface Motorower : NSObject <Motor, Rower>
{
    int           kola;
    id            kolorostyka;
    NSString* marka;
}
- (id)zainicjalizujRowerMarki:(NSString*)nazwaMarki;
+ (Motorower*)stworzMojRowerZMarka:(NSString*)nazwaMarki;
@end

Najważniejsze elementy deklaracji:

  • #import dołącza pliki nagłówkowe dodatkowo dbając, by nie były dołączane rekurencyjnie (require_once w PHP)
  • Deklaracja klasy zaczyna się dyrektywą @interface oraz kończy @end
  • po nazwie klasy umieszczamy dwukropek i nazwę klasy nadrzędnej
  • interfejsy umieszczamy po przecinku w nawiasach ostrych – <Motor, Rower>
  • Zmienne obiektu umieszczamy pomiędzy nawiasami {}
  • Po bloku ze zmiennymi umieszczamy deklaracje metod (nie zapomnijcie o średniku na końcu)

Implementacja przykładowej klasy:

@implementation Rower

- (id)zainicjalizujRowerMarki:(NSString *) nazwaMarki
{
    if (self = [super init]) {
        kola = 0;
        kolorostyka = nil;
        marka = [nazwaMarki copy];
        return self;
    }
}

+ (Rower *)stworzMojRowerZMarka: (NSString *) nazwaMarki
{
    return [[[self alloc] zainicjalizujRowerMarki:nazwaMarki] autorelease];
}
@end

Cechy charakterystyczne implementacji:

  • implementacja zawarta jest pomiędzy dyrektywami @implementation a @end
  • specyficzny sposób wywoływanie metod zostanie omówione osobno

Metody

Mamy do dyspozycji metody dla instancji obiektu oraz dla klasy. Poniżej przykładowa deklaracja metody wraz z opisem:

- (void)insertObject:(id)anObject atIndex:(NSUInteger)index
// opowiednik w PHP
function insertObject(id $anObject, NSUInteger $index) {}

Powyżej deklaracja metody dla instancji obiektu ( + na początku deklaracji oznaczałby metodę klasy) insertObject przyjmującej dwa parametry pierwszy ((id)anObject) będący wskaźnikiem. Natomiast drugi parametr o nazwie atIndex jest obiektem typu NSUInteger przypisany do zmiennej wewnętrznej index.

Podobnie jak w ruby tak i w Objective-C przyjęto koncepcje wiadomości wysyłanych do obiektów. I tak na podstawie sygnatury wybierana jest odpowiednia metoda, która powinna być wywołana w chwili wysłania wiadomości do obiektu/klasy.

[mojaTablica insertObject:obiekt atIndex:0];
//odpowiednik w PHP
$mojaTablica->insertObject($obiekt, $index);

Użycie wiadomości wysłanej do klasy (nie obiektu):

NSMutableArray*   myArray = nil;    //

// tworzenie nowej modyfikowalnej tablicy
myArray = [NSMutableArray arrayWithCapacity:0];

//Odpowiednik PHP
$myArray = NSMutableArray::arrayWithCapacity(0);

Wiadomość jest opisana pomiędzy nawiasami kwadratowymi []. Na początku jest napisany odbiorca następnie parametry. Można wykorzystać wyniki wiadomości jako obiekty w parametrach lub odbiorcach wiadomości np.:

[[myAppObject getArray] insertObject:[myAppObject getObjectToInsert] atIndex:0];
// odpowiednik w PHP
$myAppObject->getArray()->insertObject($myAppObject->getObjectToInsert(), 0);

Właściwości

Projektanci Objective-C w celu ograniczenia ilości getterów i setterów wprowadzili mechanizm właściwości. Dzięki temu możemy uniknąc tworzenia trywialnych getterów/setterów tworząc je poprzez deklaracje kompilatora. Tym samym zmniejszamy redundancje kodu przenosząc pracę na kompilator.

Właściwości definiuje się w bloku definiowania metod pliku nagłówkowego klasy (pliki *.h po nawiasie } a przed dyrektywą @end). Właściwości można definiować z pewnymi opcjami, poniżej przykłady:

@property BOOL flag;
@property (copy) NSString* nameObject;  // Kopiuje obiekt w czasie przypisania
@property (readonly) UIView* rootView;  // Tworzy tylko gettera

Dodatkową zaletą właściwości jest możliwość używania notacji z kropką np.:

mojObiekt.flaga = YES;
CGRect   ramka = mojObiekt.widok.ramka;
//Zamiast notacji
[mojObiekt setFlaga:YES];
CGRect   ramka = [[mojObiekt widok] ramka];

Lista atrybutów właściwości

  • readonly - tylko getter
  • readwrite – zarówno getter jak i setter – domyślny atrybut
  • assign – proste przypisywanie wartości – domyślne
  • retain – opcja, która umożliwia zapobieganie realokacji właściwości przez garbage collectora bez twojego pozwolenia (tylko obiekty Objective-C)
  • copy – przypisywanie wartości poprzez kopiowanie stanu obiektu
  • nonatomic – opcja ta w odwrotności do domyślnej atomic nie gwarantuje otrzymania wartości w procesie atomowym w czasie pobierania/zapisywania co może mieć znaczenie przy pracy wielowątkowej

Źródła

W następnym odcinku

W kolejnej części opisze jak uruchomić najprostszą aplikację czyli od stworzenia projektu po uruchomienie na iPhonie (ze złamanymi zabezpieczeniami).

Samouczek