Objective-C

A Wikipédiából, a szabad enciklopédiából
Objective-C
Paradigma többelvű: imperatív, objektumorientált, generikus
Tervező Brad Cox és Tom Love
Kiadó Apple Inc.
Típusosság duck, statikus típus, gyengén típusos
Fordítóprogram gcc, clang
Megvalósítások Clang, GCC
Hatással volt rá C, Smalltalk
Befolyásolt nyelvek TOM, Java, Objective-J


Az Objective-C egy teljesen objektumorientált kibővített változata a C programozási nyelvnek. A tervezők a C nyelvhez társították a Smalltalk stílusú üzenetközvetítést az objektumok között. A nyelv leginkább a Mac OS X és az iOS Operációs rendszerek fő programozási nyelve, azon belül is a Cocoa API és a Cocoa Touch API használja. Olyan Objective-C programokat, amelyek nem használják a Cocoa könyvtárakat, GCC-vel is lefordíthatók gépi kódra.

Történet[szerkesztés | forrásszöveg szerkesztése]

Az 1980-as években a strukturált programozás volt a legelterjedtebb programozási modell. Előnye az volt, hogy a programokat kisebb modulokra lehetett bontani, így olvashatóbbak voltak. Nagy hátránya az volt, hogy a kód újrafelhasználása szinte nem létezett, valamint a nagy programok megint csak olvashatatlanok voltak.

Hogy ezt kiküszöböljék, a XEROX Palo Alto-i kutatóközpontjában kifejlesztették a Smalltalk nyelvet, amely objektumorientált volt. A Smalltalk nagy hátránya, hogy a programot egy Virtuális gép (VM) futtatja, emiatt nagyon nagy a memóriafelhasználása és sokkal lassúbb is, mint egy natívan futó program.

Az Objective-C nyelvet Brad Cox és Tom Love fejlesztette ki az 1980-as évek elején. Mikor Steve Jobs elhagyta az Apple-t és megalapította a NeXT céget, megvásárolta az Objective-C licencét, ami lehetővé tette, hogy a NeXTstep operációs rendszert és minden fejlesztői alkalmazást Objective-C-ben írjanak meg. A NeXTstep ezáltal a kor legelőrehaladottabb operációs rendszere volt.

A GNU projekt 1992-ben megjelentette a NeXTstep ingyenes klónját, az OpenStep operációs rendszert, amely már tartalmazott egy Objective-C fordítót és könyvtárakat, az gnuc-obj-t.

Mikor az Apple 1996-ban megvásárolta a NeXT-et, a Mac OS X alapjául az OpenStep-et vették. Az OS tartalmazta az Objective-C-t és a NeXT fejlesztői rendszerét, a Project Builder-t (amelyből később az Xcode lett), valamint az Interface Builder-t. Ezek a programok a mai napig a Mac OS X legfontosabb fejlesztői eszközei. A Cocoa API az Objective-C osztályokra támaszkodik és a legelterjedtebb Objective-C környezet a mai napig.

Szintaxis[szerkesztés | forrásszöveg szerkesztése]

A nyelv egy nagyon vékony réteg a C nyelv fölött (csakis C és nem C++ kiterjesztés). Bármilyen C program lefordítható Objective-C fordítóval.

Az Objective-C szintaxisa a Smalltalkból ered. Minden nem objektumorientált művelet (változók, preprocesszálás, függvény deklarációk, függvényhívások) egyezik a C-ben használtakkal, míg az objektumorientált része a Smalltalk üzenetküldő mechanizmusának egyik változata.

Üzenetek[szerkesztés | forrásszöveg szerkesztése]

Az Objective-C objektumorientált modellje az objektumpéldányok közti üzenetküldésen alapul. Ez teljesen eltér a C++ stílusú programozási nyelvektől: itt nem az objektum egyik metódusát hívjuk meg, hanem egy üzenetet küldünk az objektumnak és itt van a lényeges eltérés. A Simula stílusú nyelvekben a metódus neve a fordító által pontosan meg van határozva a kódszegmensben, de a Smalltalkban és Objective-C-ben az üzenet csak egy név és futásidő alatt lesz meghatározva a tárbeli címe: a fogadó objektumnak kell feldolgoznia a kapott üzenetet. Ebből következik, hogy az üzenet küldésekor nincs típusellenőrzés, és nincs rá garancia, hogy az objektum válaszolni is fog az üzenetre. Ha nem tudja feldolgozni, akkor egyszerűen egy NULL pointert ad vissza.

C++ kód egy objektum metódusának meghívására:

foo->bar (parameter);

Ugyanez Objective-C nyelvben:

[foo bar:parameter];

Mindkét stílusnak megvan az előnye és hátránya. A Simula OOP-ben többszörös öröklődés és kisebb futásidő lehetséges, de alapértelmezetten nincs dinamikus kötés. Ugyanakkor kötelező (hacsak nem virtuális) minden metódusnak lennie egy implementációnak minden osztályban. A Smalltalk OOP lehetővé teszi, hogy az üzenetek ne legyenek implementálva. A Cocoa platform ezt kihasználja maximálisan: minden objektumnak a platform inicializáláskor elküldi az 'awakeFromNib:' üzenetet amint a program elindul, és erre az objektumok inicializálódhatnak. Ugyanakkor nem kötelező definiálni egy objektumot az üzenet küldésekor a kódban, dinamikus kötéssel a függőségeket a runtime oldja meg. Egy Objective-C üzenet feldolgozása legalább háromszor annyi időbe telik, mint egy virtuális C++ metódushívás.

Interfészek és implementációk[szerkesztés | forrásszöveg szerkesztése]

Az Objective-C nyelvben egy osztály interfésze és implementációja különálló kód-tömbökben kell legyen. Megegyezés szerint az interfészt egy header fájlban (általában .h kiterjesztéssel) míg az implementációt egy kód fájlban helyezzük el (általában .m kiterjesztéssel).

Interfészek[szerkesztés | forrásszöveg szerkesztése]

Az interfész általában a header fájlban van leírva. Szokványos hogy a fájl neve az osztály neve is egyúttal. Ha van egy Foo osztályunk, akkor ezt általában a Foo.h fájlba tesszük.

Példa egy interfész leírásra:

  @interface osztálynév : ősosztálynév {
    // változók
  }
 
  -(típus)példányMetódus1:(típus)paraméter1_neve :(típus)paraméter2_neve;
  -(típus)példányMetódus2Paraméter1:(típus)paraméter1_neve ésParaméter2:(típus)paraméter2_neve;
 
  +(típus)osztályMetódus1;
  +(típus)osztályMetódus2;
  +(típus)osztályMetódus3:(típus)paraméter_neve;
 
  @end

A '+' azt jelenti, hogy osztálymetódus, a '-' hogy példány metódusa. Az osztálymetódusok nem férhetnek hozzá a példányváltozókhoz.

Ugyanez a kód C++ nyelven:

  class osztálynév : ősosztálynév {
    // változók
 
    // Osztály (statikus) metódusok
    static void* osztályMetódus1();
    static típus osztályMetódus2();
    static típus osztályMetódus3(típus paraméter_neve);
 
    // Példány metódusok
    return_type példányMetódus1(típus paraméter1_neve,típus paraméter2_neve);
    return_type példányMetódus1Paraméterek(típus paraméter1_neve, típus paraméter2_neve);
  };

Megfigyelhetjük, hogy a példányMetódus2Paraméter1 példázza az Objective-C egyik különlegességét, hogy a paramétereket nevesíteni lehet a függvény nevében -- ennek nincs C++ megfelelője.

A visszatérési típusok lehetnek bármilyen standard C típusok, egy pointer egy Objective-C objektumra, vagy egy specifikus objektumra mutató pointer (NSArray *, NSImage *, NSString *). Az alapértelmezett típus id, ami bármilyen Objective-C objektumot jelöl.

A metódusok paraméterei kettősponttal kezdődnek, utána következik a típus majd a neve. Sok esetben érdemes megnevezni a paramétereket:

  -(void) setRange:(int)start :(int)end;
  -(void) importDocumentWithName:(NSString *)name withSpecifiedPreferences:(Preferences *)prefs beforePage:(int)insertPage

Implementációk[szerkesztés | forrásszöveg szerkesztése]

Az interfész csak a metódusok és változók neveit deklarálja; maga a kód az implementációban létezik. Általában .m kiterjesztésű fájlokba tesszük.

@implementation classname
+(típus)osztályMetódus {
    // implementáció
}
-(típus)példányMetódus {
    // implementáció
}
@end

Összehasonlítva a C++ és Objective-C közti különbségeket:

-(int)foo:(int)bar {
    return [self square_root: bar];
}
int foo(int bar) {
    return square_root(bar);
}

Itt egy példa a paraméterek nevesítésére és használatára:

-(int)changeColorToRed:(float)red green:(float)green blue:(float)blue
 
[myColor changeColorToRed:5.0 green:2.0 blue:6.0];

Példányosítás[szerkesztés | forrásszöveg szerkesztése]

Az Objective-C osztályokat két lépésben példányosítjuk: először lefoglaljuk a memóriát az új objektum számára majd inicializáljuk. Egy objektum addig nem működőképes, amíg mindkét lépést nem végeztük el. Ezeket általában egyetlen sorban meg lehet oldani:

MyObject * o = [[MyObject alloc] init];

Az alloc hívás elegendő memóriát foglal le, az init hívás felülírható, hogy a változókat inicializálhassuk:

-(id) init {
    self = [super init];
    if (self) {
        ivar1 = value1;
        ivar2 = value2;
        .
        .
        .
    }
    return self;
}

Protokollok[szerkesztés | forrásszöveg szerkesztése]

A protokollok lehetővé teszik a többszörös öröklődést. Kétféle protokoll van: ad-hoc vagy informális és fordító által szabályozott, vagy formális protokollok.

Egy informális protokoll egyszerűen egy metódus lista, amit az osztály implementálhat. A dokumentációban létezik, mivel a nyelvben nem jelenik meg. Ilyenek például az opcionális metódusok, ahol a metódus implementálása az osztály teljes működését befolyásolja.

A formális protokoll hasonló a Java vagy C# interface típusaihoz. Ez egy metódus lista amelyet az osztály felsorol implementálás céljából. A 2.0 Objective-C változatok előtt minden felsorolt metódust implementálni kellett, máskülönben a fordító hibát jelzett, ha az osztály nem implementálta minden metódusát a felsorolt protokollokban. Ez már nem kötelezö a 2.0 változattól kezdődően.

A leglényegesebb különbség a Java és C# nyelvekkel szemben, hogy egy osztály implementálhatja a protokollt anélkül, hogy deklarálta volna. A különbség kódon kívül nem látható.


Szintaxis:

@protocol Locking
- (void)lock;
- (void)unlock;
@end

Ez a protokoll a lock műveletet implementálja, amelyet a következő osztály felhasznál:

@interface Osztaly : OsOsztaly <Locking>
@end

Ez azt jelenti, hogy az Osztaly implementálni fogja a két metódust a Locking protokollból, ahogyan akarja.