Fotografický magazín "iZIN IDIF" každý týden ve Vašem e-mailu.
Co nového ve světě fotografie!
Zadejte Vaši e-mailovou adresu:
Kamarád fotí rád?
Přihlas ho k odběru fotomagazínu!
Zadejte e-mailovou adresu kamaráda:
Informace
Co jsme si o Objective C ještě neřekli...
14. května 2004, 00.00 | V minulém dílu jsme se seznámili se systémem objektů a ukázali jsme si všechny základní služby jazyka Objective C. Nyní se seznámíme se zbytkem konstrukcí, jež Objective C nabízí; ačkoli žádná z nich není pro programování bezpodmínečně nutná – jednoduché testovací prográmky jste si snadno mohli vyzkoušet už s využitím služeb, popsaných minule – dokáží programátorovi výrazně usnadnit život.
V minulém dílu jsme se seznámili se systémem objektů a ukázali jsme si všechny základní služby jazyka Objective C. Nyní se seznámíme se zbytkem konstrukcí, jež Objective C nabízí; ačkoli žádná z nich není pro programování bezpodmínečně nutná – jednoduché testovací prográmky jste si snadno mohli vyzkoušet už s využitím služeb, popsaných minule – dokáží programátorovi výrazně usnadnit život.
Několik typů, konstant a proměnných
O jednom z rozšíření, jež Objective C nabízí, jsme se již zmínili v rámci našeho příkladu "čtečky RSS na dvacet řádků": ve standardních hlavičkových souborech jsou definovány typ a hodnoty pro logické (boolovské) výrazy: jde o typ BOOL a hodnoty YES a NO. Samozřejmě jsme stále v jazyce C, takže BOOL je prostě celočíselný typ, a hodnoty YES a NO vhodná "nenula" a nula – standardní headery prostě definují
typedef signed char BOOL; #define YES (BOOL)1 #define NO (BOOL)0
Kromě typů id a Class a hodnot nil a Nil, jež již známe z minulého dílu, nabízí Objective C ještě následující typy a hodnoty:
Typy:
- SEL: vnitřní representace zprávy
- IMP: metoda (přímý ukazatel na metodu, používaný pro statický přístup)
Identifikátory:
- id self: v implementaci metody representuje objekt, který metodu zpracovává
- id super: detto, ale jeho metody jsou vyhledávány v rodičovské třídě
- SEL _cmd: v implementaci metody representuje zprávu, jež metodu vyvolala
Z typů je rozhodně důležitější SEL: jeho hodnoty přesně odpovídají identifikátorům zpráv; jinými slovy, existuje vzájemně jednoznačný převod mezi jmény zpráv (jako je třeba doubleValue, zpravaSJednimParametrem: či parser:didEndElement:namespaceURI:qualifiedName:) a hodnotami typu SEL. Z hlediska programátora bychom tedy stejně dobře mohli používat přímo textové řetězce, obsahující jména zpráv (podobně tomu je kupříkladu v Javě); hodnoty SEL však jsou mnohem efektivnější: jde totiž v zásadě o celá čísla (přesně řečeno, SEL je ukazatel, ovšem ukazatele jsou ve standardním C na celá čísla bezproblémově převoditelné). Díky tomu jsou dynamické služby Objective C, založené na hodnotách typu SEL – budeme jim říkat selektory – nesrovnatelně efektivnější, než obdobné služby Javy z java.lang.reflect.
Pro získání selektoru na základě známého jména zprávy slouží v Objective C speciální direktiva @selector, jejímž argumentem je konstantní jméno zprávy (např. tedy můžeme napsat "SEL foo=@selector(doubleValue);", povšimněte si, že "doubleValue" zde není textový řetězec, ale přímo jméno zprávy bez uvozovek). Pro přímé převody mezi hodnotami typu SEL a textovými objekty (s nimiž se podrobněji seznámíme až příště) slouží standardní funkce NSStringFromSelector a NSSelectorFromString – ty jsou však samozřejmě méně efektivní, než direktiva @selector, jež je de facto konstantou (přesněji pro puntičkáře, konstantní adresou, jejíž hodnota je určena ve fázi spojování modulů).
Typ IMP vlastně není ničím jiným, než klasickým Céčkovým ukazatelem na funkci, a využívá se v těch zcela výjimečných případech, kdy potřebujeme volat metodu rychleji, než prostřednictvím mechanismu zpráv.
Naproti tomu, identifikátory self a super používáme velmi často, a je důležité je správně pochopit; jejich popisu proto věnujeme samostatný odstavec. Řidčeji se setkáme s využitím identifikátoru _cmd; ten je typu SEL a uvnitř implementace nějaké metody vždy obsahuje selektor té zprávy, jejíž přijetí vedlo k vyvolání dané metody. Později si ukážeme jeho praktické využití na několika příkladech, ale pro tuto chvíli můžete na jeho existenci klidně zapomenout: pro základní pochopení Objective C není vůbec důležitý.
Za zmínku ještě stojí to, že self, super a _cmd jsou skutečně identifikátory a nikoli nová klíčová slova. Můžeme je díky tomu bez jakýchkoli problémů předefinovat; překladač Objective C kupříkladu bez problémů přeloží 'obyčejný céčkový' program, ve kterém je použita proměnná jménem "self" (jen to zkuste v C++ s proměnnou jménem "this"!).
Nil jako speciální příjemce
Nesmírně praktickou konvencí jazyka Objective C je to, že "neexistujícímu objektu" – tedy kterékoli z hodnot NULL, Nil, nil, 0 – můžeme bezpečně posílat jakékoli zprávy, a vůbec nic se nestane. Formálně, zaslání libovolné zprávy objektu na nulové adrese je zcela korektní prázdná operace, jež sama (bez ohledu na odeslanou zprávu) vrací hodnotu nil. To je obrovská výhoda např. proti Javě, v níž podobná situace vyvolá výjimku (nemluvě o C++, v němž může vyvolat naprosto jakýkoli problém, od pádu programu až po běh bez varování a nesprávné výsledky); v Objective C můžeme třeba v databázovém systému, spravujícím nějaký přehled občanů, napsat
id svagrovaTchyne=[[[[obcan manzelka] bratr] manzelka] matka];
a získáme správný výsledek i v případě, že daný občan nemá manželku, nebo ta nemá bratra, nebo její bratr není ženat: v Javě i v C++ bychom museli výraz proložit trojicí zhola zbytečných ifů.
Self a super
Zopakujme si z minulého dílu úryvek, týkající se přístupu k proměnným objektů:
Uvnitř implementace metod jsou přímo přístupné všechny vlastní proměnné, stačí uvést jejich jméno (takže kdybychom např. implementovali metodu třídy MyClass2, mohli bychom vracet hodnotu proměnné d příkazem "return d;").
Jak je to zařízeno? Ale jednoduše: kdykoli běží kód nějaké metody – tedy kód, vyvolaný zasláním nějaké zprávy nějakému objektu – adresa tohoto objektu je k dispozici ve zvláštní proměnné. Tato adresa pak samozřejmě umožní přístup k proměnným objektu komukoli, kdo "ví", kde uvnitř objektu je uložena která z proměnných: víme-li např., že "d" je třetí proměnnou v objektu (a ty dvě předchozí jsou typu int), bude ležet na adrese objektu plus 8. Proměnnou, obsahující adresu objektu, má přímo k dispozici i programátor, právě pod jménem self. Můžeme tedy naprogramovat třeba následující třídu:
@interface WhereAmI:NSObject @end @implementation WhereAmI -(void)report { printf("Jsem objekt třídy WhereAmI na adrese 0x%x\n",self); } @end
Zašleme-li kterémukoli objektu třídy WhereAmI zprávu report, vypíše na standardní výstup svou adresu. Je zřejmé, že pro různé objekty třídy WhereAmI bude tato adresa různá: jde o asi nejrychlejší a nejjednodušší způsob, jak např. v ladicích výpisech rozlišit, který objekt dostal zprávu a zpracovává odpovídající metodu.
Ačkoli takto proměnnou self můžeme zcela korektně použít, nejběžnější použití je trochu jiné: self nejčastěji slouží jako příjemce zpráv, jež objekt zasílá "sám sobě". Proč bychom to měli dělat? Inu, nejčastěji proto, že jsme ve třídě definovali nejprve nějaké jednoduché služby, a pak na jejich základě sestavujeme složitější – třeba takto:
@interface Angle:NSObject { // objekt representuje úhel float rad; // rozhodli jsme se udržovat hodnotu úhlu v radiánech } @end @implementation Angle -(float)radians { return rad; } // přístup "zvenku", viz @protected níže -(float)degrees { // občas se může hodit získat hodnotu ve stupních return rad/pi()*180; } -(BOOL)rightAngle { // jde o pravý úhel? return [self degrees]==90; } ...
Pokud nějaký objekt třídy Angle dostane zprávu rightAngle, posílá objektu self – tedy sám sobě – zprávu degrees, aby zjistil svou hodnotu ve stupních (a tu pak porovná s devadesátkou).
Jistě, v tomto případě bychom mohli skoro stejně pohodlně napsat také podmínku "rad==pi()/2"; přímý zápis ve stupních však je (alespoň pro programátory nematematiky) obvykle čitelnější. Kromě toho existují ještě důležitější důvody, proč se vždy vyplatí používat vlastních zpráv spíše, než přistupovat přímo k vnitřním proměnným: ten nejzákladnější si ukážeme hned.
Hlavní výhodou nepřímého přístupu k proměnným objektu (tedy s využitím posílání zpráv "sám sobě", a nikoli přímého zápisu samotné proměnné) je to, že posílání zpráv podléhá dědičnosti: to přináší nesmírnou flexibilitu. Dejme tomu, že po nějakém čase narazíme na problém: třída Angle nedává zrovna nejlepší výsledky pro úhly, přesahující 360°. Inu ovšem, zapomněli jsme úhly normalizovat – hned to napravíme v podtřídě:
@interface NormalizedAngle:Angle @end @implementation NormalizedAngle -(float)radians { while (rad>2*pi()) rad-=2*pi(); return rad; } -(float)degrees { while (rad>2*pi()) rad-=2*pi(); return rad/pi()*180; } @end
Ať už se rozhodneme získat hodnotu ve stupních či radiánech, nejprve ji normalizujeme (jistě, ještě bychom měli řešit záporné úhly, a také by to šlo efektivněji, ale to teď není podstatné); pak teprve vrátíme výsledek – v radiánech přímo, ve stupních převedený již známým způsobem.
Důležité je to, že díky použití "[self degrees]" vůbec nemusíme upravovat metodu rightAngle, a přesto bude fungovat zcela korektně jak ve staré, tak i v nové třídě – jinými slovy, pošleme-li zprávu rightAngle objektu třídy Angle, jenž representuje úhel 450°, vrátí NO; pošleme-li však tutéž zprávu objektu třídy NormalizedAngle, jenž representuje tutéž hodnotu, vrátí YES.
Je zřejmé, proč je tomu právě tak? Je to právě proto, že posílání zpráv bere v úvahu dědičnost: jakkoli se v obou případech po přijetí zprávy rightAngle nalezne týž kód metody (ze třídy Angle), po přijetí zprávy degrees se pro objekt třídy Angle použije jiná metoda, než pro objekt třídy NormalizedAngle. Jelikož implementace rightAngle posílá zprávu degrees sama sobě, využívá toho ke své výhodě: pro objekt třídy Angle dostaneme hodnotu ve stupních bez normalizace, pro objekt třídy NormalizedAngle dostaneme v téže metodě hodnotu normalizovanou.
Malý test pro pozorného čtenáře: implementace třídy Angle je docela nešikovná: lepší implementací jsme si mohli ušetřit trochu programování (jmenovitě celou implementaci metody degrees ve třídě NormalizedAngle). Víte co mám na mysli? Ano-li, skvělé, čtěte dál. Ne-li, pročtěte si posledních pár odstavců znovu ☺
Posílání zpráv "sám sobě" prostřednictvím proměnné self je skvělá věc; někdy se však nedá dost dobře použít. Představme si, že bychom ve třídě NormalizedAngle chtěli považovat za pravý také úhel 270°; v nadšení z toho, jak je posílání zpráv "sám sobě" šikovné, by se programátor začátečník mohl pokusit o následující implementaci metody rightAngle ve třídě NormalizedAngle:
-(BOOL)rightAngle { // pozor, chyba return [self rightAngle] || [self degrees]==270; }
Ouvej: pokusíme-li se skutečně poslat objektu takto implementované třídy zprávu rightAngle, program "zamrzne" (a po chvilce vypíše chybové hlášení, týkající se zakázaného přístupu k paměti). Už vidíte proč? Samozřejmě, spáchali jsme věčnou rekursi: metoda rightAngle pošle témuž objektu zprávu rightAngle, takže se znovu vyvolá metoda rightAngle, jež pošle témuž objektu zprávu rightAngle... a tak dále, teoreticky do nekonečna, prakticky jen dokud nepřeteče zásobník.
Řešením je právě druhý speciální identifikátor, super. Ten stejně jako self representuje týž objekt, který právě zpracovává metodu (přesněji, který dostal zprávu, jež k vyvolání metody vedla), ale zároveň přidává požadavek, že metoda, odpovídající právě posílané zprávě, se nesmí hledat v hierarchii tříd níže, než v nadtřídě třídy, v jejíž implementaci je super použito.
Zní to zmateně? Znamená to prostě "nezacyklit se"; pošle-li objekt sám sobě libovolnou zprávu pomocí identifikátoru super, nikdy se pro její zpracování nevyvolá metoda, implementovaná v téže třídě, v níž je super použito. Namísto toho to musí být v některé z jejích nadtříd. Díky tomu implementace
-(BOOL)rightAngle { return [super rightAngle] || [self degrees]==270; }
bude fungovat zcela korektně: díky identifikátoru super se po odeslání zprávy rightAngle nevyvolá znovu tato metoda, ale metoda nadtřídy (v našem případě tedy třídy Angle, ta, jež pouze porovná "[self degrees]" a 90).
Bývali bychom tedy kupříkladu také mohli metodu radians ve třídě NormalizedAngle implementovat takto (a bylo by to z mnoha důvodů, jež dnes nebudeme podrobně rozebírat, lepší a korektnější):
@implementation NormalizedAngle -(float)radians { float r=[super radians]; // vyvolá metodu ze třídy Angle while (r>2*pi()) r-=2*pi(); return r; } ...
Mimochodem, na rozdíl od self, což je plnohodnotná proměnná jež může být použita kdekoli, super je pouze speciální příjemce, jenž má místo jen v rámci posílání zpráv (což je nakonec samozřejmé, neboť jinde by jeho použití ani nemělo rozumný význam).
Kategorie
Vraťme se od tajů správného a špatného objektového designu zatím ještě na chvíli k vlastnímu programovacímu jazyku: velmi silný prostředek Objective C, jenž kupříkladu v takové Javě zcela chybí, jsou kategorie.
Primárním účelem kategorií je umožnit rozložení implementace jedné složité třídy do několika zdrojových souborů (potenciálně umístěných i v různých modulech). Kategorie má interface i implementaci velmi podobné těm "normálním", avšak na místě nadřízené třídy je jméno kategorie v závorkách – zde je samozřejmě povinné i pro implementaci. Kategorie nemůže definovat vlastní proměnné; má však volný přístup k proměnným, definovaným v základním rozhraní třídy.
Dejme tomu, že máme následující třídu:
@interface Xxx:Yyy { int x; } -aaa; -bbb; -ccc; @end
včetně odpovídající implementace
@implementation Xxx -aaa { return x; } -bbb { return 2*x; } -ccc { return 3*x; } @end
Pokud by pro nás bylo z jakéhokoli důvodu výhodné oddělit od sebe implementace těchto tří metod do samostatných celků, mohli bychom stejně dobře použít základní třídy a dvou kategorií – z hlediska práce s třídou Xxx a jejími instancemi by se nezměnilo vůbec nic, vše bude fungovat stejně dobře:
@interface Xxx:Yyy // základní třída -aaa; @end @interface Xxx (KategorieProMetoduB) -bbb; @end @interface Xxx (AProMetoduCcc) -ccc; @end
Ovšemže by v praxi kterákoli z kategorií mohla být v samostatném hlavičkovém souboru – ten by jen musel pomocí direktivy #import zavést hlavičkový soubor s deklarací základní třídy. Obdobně by samozřejmě byla rozdělena i implementace:
@implementation Xxx // základní třída -aaa { return x; } @end @implementation Xxx (KategorieProMetoduB) -bbb { return 2*x; } @end @implementation Xxx (AProMetoduCcc) -ccc { return 3*x; } @end
Zde by ovšem každá z kategorií jistě byla v samostatném zdrojovém souboru (jinak by bývalo nemělo valný smysl implementaci třídy do kategorií vůbec dělit).
Nejdůležitější službou, již kategorie nabízejí (a jež právě ve zmíněné Javě hrozně moc schází) je doplňování nových metod k již existujícím třídám. Ukažme si jednoduchý příklad: dejme tomu, že bychom chtěli, aby libovolný objekt dokázal reagovat na zprávu where jménem počítače, na kterém běží proces, v rámci něhož objekt existuje. V Objective C není nic jednoduššího – prostě implementujeme kategorii
@interface NSObject (ReportWhere) -(NSString*)where; @end @implementation NSObject (ReportWhere) -(NSString*)where { return [[NSProcessInfo processInfo] hostName]; // se třídou NSProcessInfo se seznámíme také později } @end
Jakmile máme kategorii hotovou (a připojenou – třeba dynamicky – do kódu aplikace), můžeme novou službu zcela volně používat u kteréhokoli objektu kterékoli třídy (jejíž nadtřídou je NSObject, ale to platí takřka pro všechny).
Hlavní hodnota kategorií (a doplňování nových metod) spočívá v tom, že díky obohacení polymorfismu umožňují využívat korektního objektového designu a vyhnout se přímým testům tříd (tedy např. obdobě javského instanceof); takovými věcmi se však budeme zabývat až později. Někdy se také může hodit schopnost kategorií změnit implementaci již existující metody; to je zase naopak tak trošku prasárna, a smysl to má pouze pro případné opravy chyb knihoven, k jejichž zdrojovému kódu nemáme přístup.
Protokoly
Protokol v zásadě není ničím jiným, než seznamem metod; používá se jako společný prvek pro specifikaci tříd, které mají mít společné metody, ale nejsou strukturálně příbuzné (čímž nahrazuje implementačně i programátorsky obtížnou vícenásobnou dědičnost C++ v tom jediném případě, kdy měla jakýsi smysl). Programátoři v Javě vlastně protokoly znají, jen jim říkají interfaces a mají k dispozici jen omezené služby (např. nemohou do interfaces ukládat metody tříd).
Protokol je definován velmi podobně jako interface (ten "náš", z Objective C), nemůže však samozřejmě obsahovat proměnné. Protokoly zato mohou mít svou vlastní dědičnost, a ta – na rozdíl od dědičnosti tříd – může být i vícenásobná (jelikož protokol nemá vlastní datový obsah, nepřináší to vůbec žádné problémy). Namísto direktivy @interface je zde použita direktiva @protocol, a případný seznam "nadprotokolů" se píše do lomených závorek:
@protocol PlusMinus -plus:objekt; -minus:objekt; @end @protocol KratDeleno -krat:objekt; -deleno:objekt; @end @protocol Aritmetika <PlusMinus, KratDeleno> -unarniMinus; @end
Protokol Aritmetika tedy obsahuje všech pět metod (plus:, minus:, krat:, deleno:, unarniMinus).
Do lomených závorek se píše seznam jmen protokolů také v interface třídy, jež má dané protokoly implementovat:
@interface Xyz:NSObject <Aritmetika> ...
Překladač pak hlídá, zda v implementaci skutečně máme všechny metody ze všech protokolů (a není-li tomu tak, vydá varování). Varování si můžeme vyžádat i v případě, kdy bychom objektu, jenž sice může být libovolné třídy, ale ta musí odpovídat některému ze známých protokolů, posílali zprávu, jež součástí protokolu není – jen musíme namísto prostého typu id použít typ kvalifikovaný jmény protokolů, opět v lomených závorkách:
id foo; id<Aritmetika> bar; [foo intValue]; // žádné varování, foo může být třeba číslo [bar intValue]; // varování: v protokolu Aritmetika není metoda intValue
Objective C nabízí ještě jedno použití direktivy @protocol: stojí-li bezprostředně za ním jméno protokolu v závorkách, získáme tak speciální objekt, který protokol representuje za běhu programu, a jehož prostřednictvím můžeme např. ověřit, zda neznámý objekt danému protokolu odpovídá nebo ne:
if ([foo conformsToProtocol:@protocol(Aritmetika)]) [foo plus:bar];
Je vhodné si uvědomit zásadní rozdíl mezi výše popsaným varováním překladače při použití deklarace id<...> a mezi testem pomocí zprávy conformsToProtocol:: varování překladače je přesně to, co nabízí např. C++: šikovná pomůcka, ale není a v principu nikdy nemůže být stoprocentně spolehlivé, neboť reflektuje pouze ty informace o objektu, jež jsou známy v době překladu. Pokud však kupříkladu deklarujeme proměnnou jako id<PlusMinus> ale ve skutečnosti pak je do proměnné uložen objekt, který protokolu neodpovídá, překladač žádné varování neohlásí (neboť to nemůže "vědět"), ale k chybě za běhu samozřejmě dojde. Běhový test pomocí metody conformsToProtocol: je naproti tomu absolutně spolehlivý, neboť je polymorfně založen na skutečném stavu objektu: správnou odpověď dostaneme vždy, bez ohledu na to, jak je objekt foo deklarován a zda jeho skutečný obsah této deklaraci odpovídá nebo ne.
Ostatní
Nakonec se zběžně zmíníme o několika zbývajících, nepříliš často užívaných vlastnostech jazyka. První z nich je direktiva @class; ta umožňuje užívat odkazů na třídy v dopředných referencích, tedy dříve, než překladač narazí na odpovídající direktivu @interface. To může být zapotřebí třeba tam, kde se dvě různé třídy nějak odkazují na sebe navzájem:
@class Xxx; @interface Yyy -(Xxx*)xxx; @end @interface Xxx -(Yyy*)yyy; @end
Proměnné objektu mohou být k dispozici pouze jeho vlastním metodám, nebo i metodám všech jeho dědiců (to jsme viděli v původní implementaci metody radians třídy NormalizedAngle), nebo – ve výjimečných případech, kdy z nějakého důvodu musíme rezignovat na objektové programování a využívat statické programátorské techniky – mohou být proměnné přístupné z jakéhokoli úseku kódu kdekoli. Možnosti přístupu k proměnným jsou určeny použitím jedné ze tří direktiv:
- @private: proměnné jsou přístupné pouze metodám objektu samotného;
- @protected: proměnné jsou přístupné i dědicům (tento přístup platí také nepoužijeme-li žádnou z direktiv);
- @public: proměnné jsou přístupné komukoli.
Jestliže z nějakého důvodu musíme rezignovat na objektový přístup, můžeme také získat neomezený přístup k proměnným kteréhokoli objektu pomocí direktivy @defs; ta se však používá tak zřídkakdy, že si její použití ani nebudeme podrobně popisovat. Podobně je tomu s direktivou @encode, jež slouží pro dynamickou identifikaci typu: dříve, než budete kteroukoli z těchto direktiv skutečně potřebovat, budete přesně vědět, kde si je najít ☺
Pro práci s distribuovanými objekty nabízí Objective C kvalifikátory in, out, inout pro deklaraci ukazatelů, kvalifikátory byref a bycopy pro deklaraci objektů, a kvalifikátor oneway pro asynchronní zprávy. O co jde si vysvětlíme až se budeme zabývat distribuovanými objekty samotnými.
Novinkou současné verse překladače je přímá podpora výjimek a kritických sekcí na úrovni jazyka s využitím direktiv @try, @catch, @finally a @throw a @synchronized. Ani těm se nebudeme věnovat nyní, ale až ve článcích, popisujících odpovídající služby.
Poslední specialitou Objective C je schopnost vytvářet statické objekty reprezentující textové řetězce na základě zápisu @"... text ...". Již jsme se o tom zběžně zmínili; podrobněji se na to podíváme příště, až si ukážeme, jak přesně v Objective C objekty vznikají a zanikají.
Obsah seriálu (více o seriálu):
- Nastal čas na kakao...
- Tak nejdřív kakao ochutnáme...
- Programovací jazyk C: velmi, velmi stručně
- Objective C: to si vysvětlíme podrobněji
- Co jsme si o Objective C ještě neřekli...
- Nastal čas na kakao - Vznik a zánik objektů
- Nastal čas na kakao - Kopírování objektů
- Nastal čas na kakao - Skryté podtřídy
- Nastal čas na kakao - Základní služby objektů
- Nastal čas na kakao - Jak správně psát v Objective C
- Nastal čas na kakao - Jak správně importovat
- Nastal čas na kakao - Podtřídy, delegáti, vkládání, jak se to rýmuje?
- Nastal čas na kakao - Využití kategorií namísto dědičnosti
- Nastal čas na kakao - Vkládání objektů a přesměrování zpráv
- Nastal čas na kakao - Inicializace a rušení objektů
- Nastal čas na kakao - Metody initWith... a designovaný inicializátor
- Nastal čas na kakao - Inicializace: tipy a triky
- Nastal čas na kakao - Accesory: přístup k proměnným instancí
- Nastal čas na kakao - Šedá je teorie, zelený je strom života...
- Nastal čas na kakao - Více o XCode: inspektory
- Nastal čas na kakao - Aplikace RSS2: datový model
- Nastal čas na kakao - Aplikace RSS: implementace datového modelu
- Nastal čas na kakao - Aplikace RSS: parsování XML
- Nastal čas na kakao - Interface Builder a uživatelské rozhraní
- Nastal čas na kakao - Interface Builder: atributy objektů
- Nastal čas na kakao - Interface Builder: atributy objektů
- Nastal čas na kakao - Druhý kontrolér a dokončení aplikace
- Nastal čas na kakao - Drobná vylepšení a zdokonalení...
- Nastal čas na kakao - Ladění
- Nastal čas na kakao - Třídy Foundation Kitu
- Nastal čas na kakao - Třídy Foundation Kitu (2)
- Nastal čas na kakao - Textové řetězce: NS(Mutable)String
- Nastal čas na kakao - Čísla, binární data a další...
- Nastal čas na kakao - Archivace objektů
- Nastal čas na kakao - Trocha magie, aneb distribuované objekty
- Nastal čas na kakao - Málem bychom zapomněli: NSAutoreleasePool
- Nastal čas na kakao - Zpracování výjimek: NSException
- Nastal čas na kakao - NSInvocation a černá magie
- Nastal čas na kakao - Kakao v Tygrovi
- Nastal čas na kakao - Notifikace: nepřímé předávání zpráv
- Nastal čas na kakao - NSUserDefaults
- Nastal čas na kakao - Co nového ve Foundation Kitu
- Nastal čas na kakao – s Intelem, s Intelem, jedeme do...
- Co nového v Xcode
- Začínáme s AppKitem
- Jak MVC v Kakau vypadá doopravdy?
- Jak MVC v Kakau vypadá doopravdy: dokončení
- Přehled tříd AppKitu
- Nastal čas na kakao - Přehled tříd AppKitu 2
- Přehled tříd AppKitu 3: zbývající třídy GUI
- Přehled tříd AppKitu 4: textový systém
- Nastal čas na kakao - Přehled tříd AppKitu 5: hlavně grafika
- Přehled tříd AppKitu 6: dokumentový systém
- Přehled tříd AppKitu 7: dokončení
- Pojmenované vlastnosti objektů
- Pojmenované vlastnosti objektů: implementace
- Pojmenované vlastnosti objektů: relace 1:N
- Pojmenované vlastnosti objektů: řazení jmen a agregační funkce
- Sledování změn objektů
- Sledování změn objektů – ukázka
- Sledování změn objektů – zdrojový kód
- Sledování změn objektů: kód modelu
- Sledování změn objektů: přímý přístup
- Kontroléry a vazby
- Vázání vazeb
- Další vazby s jednoduchým kontrolérem
- Implementace a použití převodu hodnot
- Validace hodnot
- Validace a chyby, a jedna hezká vazba...
- Práce s polem objektů
- Základní vazby NSArrayControlleru
- Převodníky, přepínače, placeholdery
- Mírná vylepšení v mezích zákona
- Objective C 2.0 - novinky z Leoparda
- NSTreeController
- Programování v Cocoa - Pár tipů a triků
- Programování v Cocoa - Základy kreslení
- Kterak nakreslit modrý obdélník...
- Další služby pro kreslení
- Obrázky a písmenka...
- Události a myš
- Lepší práce s myší
- Události klávesnice
- Input Management
- Příkazy a schránka
- Další události
- Táhni a padni
- Byli jsme na tahu; nyní padneme.
- Zvolme si, jak vhodit
- Drobnosti a chybičky
- Speciální případy tahání či házení
- Kterak táhnout něco, co neexistuje?
- Jak na sítě...
- NSURLConnection
- Safari za minutu
- Služby WebKitu
- Kakao v Leopardu
- Druhé Objective C
- Druhé Objective C: různé drobnosti
- Druhé Objective C: kategorie a protokoly
- Druhé Objective C: nový příkaz cyklu
- Druhé Objective C: atributy a accesory
- Druhé Objective C: atributy a accesory
- 64 je dvakrát 32
- Ubicumque dulce est, ibi et acidum invenies...
- Irbis: že prý žádné novinky?
- Blok sem, blok tam, nám už je to všechno jasné...
- Bloky jsou i v AppKitu
- Irbis a Foundation Kit
- Kde jsou má data?
- Kde jsou má data? V NSCache!
- Soubor, jméno, URL, jak se to rýmuje...
- Další podpora NSURL
- Zabíjení!
- A máme tady i...OS!
- Systémové prvky GUI
- Programování pro iOS 1. díl - Rozdíly mezi "i" a "Mac"
- Programování pro iOS - 2. Začínáme programovat
- Programování pro iOS - 3. základní ovladače a propojení GUI s kódem
- Programování pro iOS - 4. Varovná hlášení
- Programování pro iOS - 5. Rámce a jejich řídicí objekty
- Programování pro iOS - 6. Ukládání dat
- Programování pro iOS - 7. Správa paměti a starý restík
- Programování pro iOS - 8. Dokončení aplikace
- Programování pro iOS - 9. Jak dostat aplikaci do iPhone
- Programování pro iOS - 10. Instalace aplikace do cizího iPhone
- Programování pro iOS - 11. Jak dostat aplikaci do libovolného iPhone
- Programování pro iOS - 12. Touching!
- Programování pro iOS - 13. Kreslíme na iPhone
- Programování pro iOS - 14. Udělejme gesto
- Programování pro iOS - 15. Další gesta
- Programování pro iOS - 16. Více prstů, více zábavy
- Programování pro iOS - 17. Podpora standardních gest
- Programování pro iOS - 18. Recognizery v iOS
- Programování pro iOS - 19. Další standardní recognizery
- Programování pro iOS - 20. Co nového v iOSu
- Programování pro iOS - 21. "Multitasking"
- Programování pro iOS - 22. Nulla est honesta avaritia nisi temporis
- Programování pro iOS - 23. Jak se aktivovat, jsme-li v pozadí
- Programování pro iOS - 24. Zbývající drobnosti
- Programování pro iOS - 25. Řídicí objekty rámců
- Programování pro iOS - 26. Jak se dělá UIViewController
- Programování pro iOS - 27. Kde vzít rámce
- Programování pro iOS - 28. Základní služby
- Programování pro iOS - 29. Práce s rámci
- Programování pro iOS - 30. Rotace zařízení
- Programování pro iOS - 31. Správa paměti v rámcích
- Programování pro iOS - 32. Řídicí objekt pro tabulky
- Programování pro iOS - 33. Řídicí objekt pro strom
- Programování pro iOS - 33. Více o UINavigationControlleru
- Programování pro iOS - 35. Ještě jednou UINavigationController
- Programování pro iOS - 36. Po navigátoru taby
- Programování pro iOS - 37. Více o UITabBarControlleru
- Programování pro iOS - 38. Dokončení UITabBarControlleru
- Programování pro iOS - 39. UIPopoverController
- Programování pro iOS - 40. Další triky UIPopoverControlleru
- Programování pro iOS - 41. Zbývající služby UIPopoverControlleru
- Programování pro iOS - 42. UISplitViewController
- Programujeme v
iTunesXcode 4 - Programování pro iOS - 44. Předvolby Xcode 4
- Programování pro iOS - 45. Práce v Xcode 4
- Xcode 4: projekt a cíle
- Xcode 4: práce s cíli
- Xcode 4: Build Settings
- Xcode 4: Build Phases
- Xcode4: Build Phases podruhé
- Xcode 4: Co jsou to Build Rules?
- Xcode4: taje editoru
- Xcode4: automatické doplňování v editoru
- XIBy chyby
- Více o XIBech
- Editor XIBů
- Inspektory pro XIBy
- Vazby mezi objekty v XIBech
- Vazby mezi objekty v kódu
- Paletky Xcode pro XIBy
- Xcode 4: levý sloupec
- Xcode 4: okno Organizer
- Xcode 4: okno Organizer, část druhá
- Xcode 4: co je to Workspace?
- Xcode 4: základy schémat
- Xcode 4: akční schémata