Objective- C Bereczki Gréta Tamara Programozási nyelvek és paradigmák 2. GY 2013-2014 / tavasz
Objective- C Teljesen objektumorientált, a C nyelv bővített változata, vagyis ami működik C- ben, az Objective- C- ben is Az objektumorientált része a Smalltalk üzenetküldő mechanizmusának egyik változata 1980- as évek elején kezdték el fejleszteni
Motiváció- Miért Objective- c? Harmadik a programozási nyelvek népszerűségét mutató Tiobe listán 2011, 2012 – ben az év programozási nyelve Mac OS X és iOS fő programozási nyelve Növekvő népszerűségnek örvend
Motiváció
Hello World! #import <stdio.h> //include helyett import int main( int argc, const char *argv[] ) { printf(„Hello World!”) return 0; }
Hello World! #import <Foundation/Foundation.h> //include helyett import int main( int argc, const char *argv[] ) { @autoreleasepool NSLog (@"Hello, World!"); return 0; }
Foundation keretrendszer Alapvetően osztályok gyűjteménye, amelyek a fejlesztés könnyítését szolgálják. A NeXT Computers cég fejlesztette ki a NeXTStep részeként. Miután az Apple megszerezte a NeXT céget, hamar a Mac OS X és az iOS fejlesztés szerves része lett. A NeXT céget egyébként Steve Jobs hozta létre miután kirúgták az Apple cégtől. A keretrendszer minden osztálya az NS előtaggal kezdődik a NeXTStep-ből adódóan.
Azonosítók Kezdőkarakter A-Z, a-z vagy _ , majd további betűk, számok és _ Nem szerepelhet: @, $, % Kis- és nagybetű érzékeny Határoló jel a ; , tetszőleges számú írható belőle egymás után. Megjegyzés: //, /* */ Megengedettek a többsoros sztring literálok.
Kulcsszavak A kulcsszavak egy részét a C nyelvből örökölte Az Objective- C által bevezetett kulcsszavakat @ jellel kezdjük, így megkülönböztetve őket a C nyelv kulcsszavaitól Kulcsszavak nem szerepelhetnek azonosítóként
Kulcsszavak
C nyelvből örökölt típusok Egész típusok: char unsigned char signed char int unsigned int short unsigned short long unsigned long Valós típusok: float double long double Void típus
Típusok A nyelv statikus típusozású int i, j, k; i=j=k=5; // i, j, k értéke 5 char c, ch; float f, salary; const double d=12; // konstansok a C nyelvhez hasonlóan Van BOOL típus, ennek értéke YES vagy NO lehet id típus: a C- beli void* megfelelője, minden objektum típusa id, futási időben derül ki a konkrét típus
Típusok char *str=“This is a C string” A string típus a C nyelvhez hasonlóan: char *str=“This is a C string” vagy char str[]=“This is a C string.” Objective- C- ben megjelenik az NSString osztály, amely számtalan metódussal segíti a stringek kezelését. NSString *str=@“This is an Objective- C string.” Az NSString immutable típus, azonban létezik mutable változata is, az NSMutableString.
Típusok Az NSNumber a C-beli numerikus típusok wrapper osztálya Szükség van rá például azért, mert az NSArray vagy NSSet tárolókban csak így tárolhatunk numerikus értékeket NSNumber *anInt = @ 2147483647; NSNumber *aFloat =@ 26.99F; NSLog(@"%@", anInt); //használható %@ %i helyett NSLog(@"%@", aFloat);
Típusok Az NSInteger az NSNumber- el szemben nem egy osztály, hanem egy primitív típus, ami megfeleltethető az int típusnak. Általában az NSInteger- t ciklusokban, számításoknál, stb. használjuk, más esetben érdemes az NSNumber- t használni.
Típusok Implicit típuskonverzió az alábbi szabályok alapján: int-> unsigned int->long-> unsigned long-> long long-> unsigned long long-> float-> double-> long double Explicit típuskonverzió lehetséges: double y=4.5; int x=(int)y;
Felsorolási típus A felsorolási típust az enum kulcsszó vezeti be typedef enum { HONDA, NISSAN} CarModel; int main(int argc, const char * argv[]) { CarModel myCar = NISSAN; switch (myCar) case HONDA: case NISSAN: NSLog(@"You like cars?"); break; default: break; } return 0;
Vezérlési szerkezetek Elágazás, elől- és hátultesztelő ciklus, számláló ciklus (for), switch- case a C nyelv alapján. Használható a goto utasítás is, persze csak nagyon indokolt esetben. Újdonság a for- in ciklus, amely gyűjtemények gyors bejárását teszi lehetővé NSArray *models = @[@"Ford", @"Honda", @"Nissan”]; for (id model in models) { NSLog(@"%@", model); }
Típuskonstrukciók Bár használható a C stílusú tömb, mégis leggyakrabban a gyűjtemények a Foundation keretrendszer osztályainak példányai. NSArray *germanMakes = @[@"Mercedes-Benz", @"BMW", @"Porsche", @"Opel", @"Volkswagen", @"Audi"]; for (int i=0; i<[germanMakes count]; i++) { NSLog(@"%d: %@", i, germanMakes[i]); }
Típuskonstrukciók Az NSArray immutable típus, ezért dinamikusan nem lehet elemeket hozzáadni sem elvenni. Erre a célra használható az NSMutableArray NSMutableArray *brokenCars = [NSMutableArray arrayWithObjects: @"Audi A6", @"BMW Z3", @"Audi Quattro", @"Audi TT", nil]; [brokenCars addObject:@"BMW F25"]; [brokenCars removeLastObject]; Minden gyűjtemény rendelkezik létrehozó függvényekkel. Az NSArray esetében ilyen például az array, arrayWithArray, arrayWithObjects. Az arrayWithObjects például létrehoz és visszaad egy tömböt, ami a megadott objektumokat tartalmazza.
Típuskonstrukciók Minden gyűjtemény alapvetően immutable, de létezik mutable változata is (NSMutableArray, NSMutableSet, stb.). A rekord típuskonstrukciónak a C- hez hasonlóan a struct, az úniónak pedig a union felel meg.
Pointerek Használhatók a C típusú pointerek, bár legtöbb esetben nincs rájuk szükség int year = 1967; int *pointer = &year; NSLog(@"%d", *pointer); pointer = NULL; Ajánlott az Objective- C osztályok használata. Ezeket mindig mutatókon keresztül kezeljük. NSString *anObject; anObject = nil; // a C- ben használt NULL helyett nil- t használunk
Pointerek Pointerek összeadása, inkrementálása hasonló eredménnyel jár, mint a C/C++ nyelv esetében. Dereferencia: *<pointernév> A C++ nyelvből ismert referenciák nem használhatóak.
Memóriakezelés Memóriát az alloc kulcsszó segítségével foglalhatunk, és a release kulcsszóval szabadíthatunk fel NSString *str=[[NSString alloc] initWithString:@"My string"]; [str release] A lefoglalt memóriaterületek felszabadítása történhet automatikusan is. Ehhez létre kell hoznunk egy NSAutoreleasePool típusú objektumot. Ha erre az objektumra meghívjuk a drain műveletet, akkor minden lefoglalt memóriaterületre meghívódik a release utasítás.
Memóriakezelés #import <Foundation/NSString.h> int main( int argc, const char *argv[] ) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; NSString *str1 = @"constant string"; NSString *str2 = [NSString stringWithString: @“automatically managed string"]; NSString *str3 = [[NSString alloc] initWithString: @"self managed string"]; [str3 release]; // memória felszabadítása [pool drain]; // pool felszabadítása } return 0;
Memóriakezelés Ha egy objektumra még szükség van, akkor a retain utasítás használata biztosítja, hogy az ne kerüljön felszabadításra. Minden alloc, retain művelet eggyel növeli a referenciaszámlálót az adott objektumra. Annyiszor kell majd meghívni a release műveletet, amennyi a referenciaszámláló értéke. Ennek számontartása azonban nehézkes. Más nyelvekből ismert Garbage Collector funkció nincs.
Memóriakezelés - ARC Az Automatic Reference Counting rövidítése, tetszőlegesen be- és kikapcsolható. Előfordítás során hozzáadja a megírt kódhoz a szükséges retain/ release műveleteket, így megkönnyítve a felhasználó dolgát NSObject *obj = [[NSObject alloc] init]; // egyéb műveletek [obj release]; // ARC által automatikusan hozzáadva fordítás során
Memóriakezelés- ARC ARC- ban az NSAutoreleasePool osztály helyett egy @autorelease blokkot használunk. @autoreleasepool { NSLog (@"Hello, World!"); return 0; }
Alprogramok Az egyszerű alprogramok ugyanúgy használhatók, mint a C nyelvben float multiply (int, int) { return x * y; } int main (int argc, const char * argv[]) @autoreleasepool float result; result = multiply( 10, 20 ); return 0;
Alprogramok Függvények túlterhelése nem lehetséges. Operátorok túlterhelése sem lehetséges. A Java nyelvhez hasonlóan csak érték szerinti paraméterátadás létezik. Pointerek használatával azonban elérhető a referencia szerinti paraméterátadásnak megfelelő hatás.
Osztályok Lehetőség van a specifikáció(interfész) és az implementáció szétválasztására külön fordítási egységbe Specifikációt egy .h kiterjesztésű fájl tartalmazza Implementációt(interfészt) egy .m kiterjesztésű fájl tartalmazza Minden objektum közös őse az NSObject
Osztályok Az interfész minden esetben az @interface kulcsszóval kezdődik és az @end kulcsszóval végződik Az adattagokat a blokkon belül, a metódusokat azon kívül deklaráljuk Az adattagok alapértelmezetten protected elérésűek, de módosítható @public, @private, @protected
Osztályok @interface osztálynév : ősosztálynév { // alapértelmezetten protected elérésű változók } -(típus)példányMetódus1:(típus)par1_neve; +(típus)osztályMetódus1; +(típus)osztályMetódus2:(típus)par_neve; @end
Osztályok Az előző példa C++ megfelelője class osztálynév : public ősosztálynév { protected: // változók // public: static void* osztályMetódus1(); static típus osztályMetódus2(típus par_neve); return_type példányMetódus1(típus par1_neve); };
Osztályok Az interfészben megadott metódusokat az implementációban definiáljuk. @implementation classname +(típus)osztályMetódus:(típus)par1_neve { // implementáció } -(típus)példányMetódus:(típus)par_neve @end
Osztályok Nincs megszokott konstruktor, azonban használható egy inicializáló művelet: - (id) init { self = [super init]; //ősosztály inicializálása if (self != nil) //ősosztály sikeres inicializálása esetén //inicializálás } return self;
Osztályok „Destruktor”: csak abban az esetben szükséges, ha nem alkalmazunk automatikus memóriafelszabadítást - (void)dealloc { // lefoglalt objektumok felszabadítása [super dealloc]; }
Osztályok Osztály példányosítás: MyObject *o = [[MyObject alloc] init]; E helyett egyszerűsítésként használható: MyObject *o = [MyObject new]; Ha egy metóduson belül az osztály egy másik metódusát szeretnénk hívni a self változót kell használnunk. A C++ nyelven használt this mutatóval szemben, amely mindig az adott objektumra mutat, ez a program tetszőleges pontján megváltoztatható.
Metódusok A metódusok nagyban különböznek az egyszerű függvényektől.
Metódusok Metódus példa: -(void) printFirstName: //függvény neve (NSString *) firstName //első paraméter andLastName: //függvény neve (NSString *) lastName; //második paraméter Itt jön be a Smalltalk üzenetküldés mintája. Ennek szintaktikája: [fogadó üzenet]. Kettőspont után paramétereket adhatunk meg. Az előző metódus hívása: Person *p=[[Person alloc] init] [p printFirstName:@”Emily” andLastName:@”Williams”];
Metódusok Szintaktikus cukorkaként a metódusok hívása leírható a más programozási nyelvekből megszokott módon is: p.printName(@”Emily”,@”Williams”); Metódusok tulterhelése nem lehetséges, azonban elérhető ahhoz hasonló hatás, hiszen a paraméterek neve is hozzátartozik a függvény nevéhez. -(void)encodeFloat:(float)realv forKey:(NSString *)key -(void)encodeInt:(int)intv forKey:(NSString *)key
Osztályok A @property kulcsszóval jelölt adattagokhoz a fordító automatikusan generál getter és setter műveleteket, ha azt az implementációban a @synthesize kulcsszóval jelöljük. A setter művelet az adattag nevéből és a set szóból áll, a getter művelet neve pedig az adattag neve. @implementation Car @synthesize model = _model; ….. Car *toyota = [[Car alloc] init]; // autó léterhozása [toyota setModel:@"Toyota Corolla"]; //modell beállítása NSLog(@"Created a %@", [toyota model]); //modell kiiratása a //getter művelet felhasználásával
Öröklődés A gyerek osztály mindent örököl a szülő osztálytól. Többszörös öröklődés nincs, ez azonban megoldható protokollok segítségével. @interface InheritedClass : BaseClass { .... } .... @end
Öröklődés Virtuális függvények nincsenek, vagyis igazából csak virtuális függvények vannak. A leszármazottban tetszőlegesen felülírhatjuk az ős műveleteit, példányosításkor a megfelelő változat fog meghívódni. Felülírásnál figyelni kell arra, hogy a felülírt metódusnak pontosan annyi, ugyanolyan nevű argumentuma kell legyen, valamint a visszatérési értéknek is egyeznie kell. A leszármazottban az ősre a super kulcsszóval hivatkozhatunk.
Protokollok Ezek a más nyelvekből ismert interfészek megfelelői. Metódusokat deklarál, amelyeket más osztályoknak kell megvalósítania. Az @optional, @required kulcsszavakkal megjelölhetjük, hogy mik azok a metódusok, amiket kötelező, illetve nem kötelező megvalósítani. Az alapértelmezett beállítás a kötelező.
Protokollok @protocoll myProtocoll //protokoll - (void) requiredMethod; @optional - (void) optionalMethod; (void) anotherOptionalMethod; @required - (void) anotherRequiredMethod; @end //protokoll megvalósítás jelölése @interface ClassName : ItsSuperclass < protocol>
Protokollok Egy osztály tetszőleges számú protokollt megvalósíthat: @interface ClassName : ItsSuperclass < protocol1, protocol2, protocol3….>
Köszönöm a figyelmet!