Zpět Obsah Další

Z čeho se kakao vlastně pije?


V dosavadních dílech našeho seriálu jsme se seznámili se základy API Cocoa — víme, jak objekty vytvářet, jak s nimi pracovat i jak je rušit; až se seznámíme s konkrétními knihovními třídami, mohli bychom rovnou začít programovat... skoro. Ještě si musíme ukázat konkrétní prostředky, jež pro tvorbu programů budeme používat: nestačí vědět jak napsat zdrojový program, musíme také vědět, jaký editor na to máme k dispozici, a jak se ze zdrojových textů dá vytvořit ("zbuildovat") hotová aplikace.

Dnes se proto blíže seznámíme s prostředky, jež jsou pro programování v Cocoa k dispozici: ukážeme si centrální aplikaci ProjectBuilder, jež integruje všechny ostatní služby a jež obsahuje velmi kvalitní editor zdrojových textů; seznámíme se i s aplikací InterfaceBuilder, jež (spolu s plně objektovým systémem) umožňuje velmi pohodlné a efektivní visuální programování.

Nebudeme se příliš podrobně věnovat konkrétním službám a jejich detailnímu rozhraní — na úrovni tohoto článku není zajímavé, že se např. služba vyhledávání volá kombinací Shift-Command-F nebo konkrétní obsah odpovídajícího okna; podstatnější je paleta možností, kterou nabízí.

ProjectBuilder si popíšeme ve čtyřech hlavních odstavcích:

Co je to správa projektu?

Základem vývoje aplikací v systému Cocoa je aplikace ProjectBuilder. V původním NeXTStepu skutečně ProjectBuilder nedělal vůbec nic jiného, než vlastní správu projektu, a pro všechny ostatní činnosti volal externí aplikace. Dnes systém Cocoa přijal určitý kompromis: ukázalo se, že je výhodné přímo do ProjectBuilderu integrovat editor zdrojového kódu a grafické uživatelské rozhraní pro debugger (s editorem se seznámíme níže, zatímco ladění si necháme na příští díl našeho seriálu). Hlavním úkolem však pořád zůstává správa projektu.

O co vlastně jde? Je to jednoduché: každý projekt sestává z řady souborů a informací: jsou v něm zdrojové kódy, jsou v něm odkazy na hlavičkové soubory a knihovny (nebo javské "packages"), jsou v něm další soubory, jež se mají stát součástí hotové aplikace (např. help nebo šablonové dokumenty), je v něm řada dalších pomocných dat (třeba dokumentace)...

Úkolem ProjectBuilderu právě je udržet přehled v tomto balíku zdrojů a umožnit jeho pohodlnou a přehlednou údržbu. Povšimněte si hned zpočátku jedné nesmírně důležité věci: vůbec jsme se zatím nebavili o překladu zdrojových textů! Většina integrovaných vývojových systémů je postavena kolem konkrétního překladače určitého jazyka. Ne tak ProjectBuilder — v něm můžeme stejně snadno spravovat zdrojové texty v libovolném jazyce; i součástí jediného projektu může být bez omezení řada zdrojových souborů v různých jazycích:

PB1

Pro přehled v nejrůznějších zdrojích, jež mohou být součástí projektu, dokáže ProjectBuilder spravovat řadu samostatných kategorií; jejich seznam je rozšiřitelný, avšak mezi nejběžnější patří:

Pro některé kategorie nabízí ProjectBuilder speciální služby. Např. soubory z kategorie "Headers" mohou být označeny jako předkompilované (to je asi zřejmé), nebo jako "Project" či "Public" soubory. Volba "public" je vhodná pro knihovny a frameworky — jsou to ty soubory, jež se stanou součástí hotové  knihovny (je zřejmé, že v projektu může být kromě nich řada privátních hlavičkových souborů).  Hlavičkové soubory označené "project" mají jinou výhodu: jsou přístupné odkudkoli z celého (hierarchického a obecně velmi složitého) projektu aniž bychom potřebovali znát jejich přesné umístění — postačí napsat jen #include "jméno souboru".

Podobně kterýkoli ze souborů, ukládaných do hotové aplikace (Images, Sounds, Resources, ale i Interfaces) může být označen jako "lokalizovatelný"; ProjectBuilder pak automaticky podporuje udržování řady versí tohoto souboru pro různé jazyky (včetně češtiny), a API Cocoa (jak si ukážeme později při popisu třídy NSBundle) zajistí automatické použití vhodné jazykové verse, aniž by se o to musel programátor dále starat.

PB2

Efektivní a v pravém smyslu slova luxusní správa těchto kategorií — přidávání a odebírání souborů, volání odpovídajících aplikací pro editaci (např. poklepeme-li na obrázek v kategorii Images, ProjectBuilder automaticky spustí vhodný obrazový editor) atd. je hlavním a základním úkolem ProjectBuilderu.

Překlad a "buildování"

Kromě toho ProjectBuilder nabízí i pohodlné grafické uživatelské rozhraní pro překlad a další zpracování projektu. Ovšem, to neznamená, že by ProjectBuilder obsahoval nebo sám volal nějaké překladače — takové řešení, jakkoli běžné v jiných prostředích, je mimořádně nevhodné: omezuje totiž zásadním způsobem flexibilitu. ProjectBuilder namísto toho geniálně využívá toho, co již je dávno hotové a vyzkoušené: volá totiž standardní příkaz make, a jen připraví "Makefile", obsahující seznam všech souborů ve všech kategoriích (a ostatních nastavení) ve vhodných proměnných.

ProjectBuilder obsahuje snadno přístupné služby pro základní operace "make all" (vytvoření programu), "make install" (instalace) a "make clean" (odstranění všech generovaných souborů); je ale možné velmi snadno přidat jakékoli další služby.

Čtenáři, již znají systém make, vědí, že díky tomu jsou možnosti ProjectBuilderu prakticky neomezené. Připravíme-li vhodné šablony pro "makefile", není nejmenší problém — pokud by to někomu vyhovovalo — třeba dívat se na sadu textových dokumentů jako na projekt, a při jeho "buildování" vygenerovat obsah, rejstřík, a připravit PostScriptové soubory pro sazbu...

Je již také zřejmé, proč lze v ProjectBuilderu využívat zdrojové soubory v libovolném programovacím jazyce (pro který máme k dispozici překladač) — systém "makefiles" sám podle přípony zdrojového souboru nalezne a spustí odpovídající překladač, a sám korektně spojí všechny přeložené moduly do výsledného produktu.

Další nesmírná výhoda standardního systému make spočívá v tom, že můžeme všechny služby využívat přímo z příkazové řádky nebo ze scriptů. Chceme-li např. uvolnit místo na disku tím, že ve všech projektech zrušíme generované soubory, můžeme snadno napsat script, který vyhledá všechny projekty a v každém provede "make clean".

Editor zdrojových textů

Bylo by logické, aby ProjectBuilder pro úpravy zdrojových textů volal externí editor — stejně, jako volá např. externí editor obrázků pro soubory z kategorie Images. Ačkoli je to stále možné — součástí předvoleb ProjectBuilderu je i specifikace editoru zdrojových textů, a je řada programátorů, kteří nedají dopustit na svůj Emacs — ukázalo se, že je obvykle pohodlnější, nabízí-li tyto služby přímo sám ProjectBuilder.

Jeho součástí je proto velmi pohodlný a výkonný editor zdrojových textů, který rozumí syntaxi C, Objective C, C++, Javy a WebScriptu, a který nabízí řadu služeb, jež by bylo do obecných editorů obtížné nebo nemožné zařadit.

Typickým příkladem je třeba automatické doplňování symbolů: jednou z nesmírně pohodlných služeb ProjectBuilderu je to, že můžeme napsat jen několik prvních znaků slova, a ProjectBuilder je po stisknutí klávesy Esc automaticky doplní na vhodný identifikátor. Tato služba byla v NeXTStepu k dispozici "odjakživa" v rámci jednoho zdrojového textu; nový ProjectBuilder však dokáže identifikátory pro doplnění vyhledávat i na knihovnách a frameworcích! Chceme-li tedy např. zapsat jméno kódové tabulky "NSUnicodeStringEncoding", stačí zapsat "nsuni" a stisknout Esc (je-li možností více, ProjectBuilder zobrazí jejich počet a nabízí je postupně):

PB3

Je zřejmé, že externí editor tuto službu dost dobře nemůže nabízet: na rozdíl od ProjectBuilderu totiž "neví", které frameworky jsou součástí projektu, a proto se v nich mají identifikátory hledat. Prohledávat všechny frameworky v systému by sice bylo možné, ale krajně nepraktické, protože editor by pak nabízel i ty identifikátory, jež v daném projektu vůbec nemají co dělat.

Nemělo by smysl popisovat všechny služby editoru zdrojových textů, který je součástí ProjectBuilderu — předně, rozsah tohoto článku je omezen, a služeb je skuečně mnoho; navíc, v nových versích systému se často objevují služby nové nebo vylepšené. Jako lahůdku na konec si proto už ukážeme jen jednu službu, jejíž rozsah opět výrazně přesahuje odpovídající možnosti jiných prostředí: prohledávání projektu.

Je celkem bežné, že můžeme vyhledat nějaký text "v celém projektu", nebo že si můžeme nechat zobrazit dokumentaci k zadané službě ze standardních knihoven. ProjectBuilder obě služby geniálně integruje dohromady, a doplňuje k nim řadu dalších možností.

Předně, uživatel se může rozhodnout hledá-li prostě libovolný výskyt daného symbolu, nebo jeho definici, nebo všechny odkazy na něj (to je možné díky tomu, že ProjectBuilder rozumí syntaxi běžně užívaných jazyků). Při hledání definice se prohledává i dokumentace a případné hlavičkové soubory všech frameworků, jež jsou součástí projektu: hlavní výhodou je to, že jsou tak automaticky k dispozici popisy a definice všech symbolů z použitých knihoven (a to i když se jedná o nestandardní, naše vlastní nebo 3rd party knihovny) — a naopak, symboly z knihoven, jež součástí projektu nejsou, se nám do hledání nepletou: např. pro obyčejný program bez grafického uživatelského rozhraní je "NSWindow" identifikátor bez zvláštního významu.

Nadto lze pro určení hledaného textu využít regulární výrazy; pro ty, kdo je neznají, jde o standardizovaný způsob, jak určit téměř libovolný vyhledávací vzor: chceme třeba vyhledat všechny výskyty funkce "foo", jejímž argumentem je číslo s exponentem? Žádný problém — prostě vyhledáme výraz "foo(-?[0-9.]*[eE]-?[0-9]*)":

PB4

Povšimněte si, že ProjectBuilder korektně našel a označil oba výskyty na jediném řádku v souboru Legacy.cpp. To, že jsou oba výskyty zobrazeny v okně na samostatných řádcích, je úmysl — díky tomu se pak můžeme snadno rozhodnout, budeme-li chtít provést případnou záměnu text v obou výskytech, nebo jen v jednom z nich (a v kterém), či ani v jednom — prostě ty požadované označíme myší.

V ProjectBuilderu lze navíc využít regulární výrazy i pro záměny: chceme-li třeba pro konsistenci API v celém projektu navzájem prohodit oba argumenty funkce "bar", ať jsou jakékoli, použijeme vyhledávací řetězec "bar(\([^,]\),\([^,]\))" a záměnu "bar(\2,\1)"...

InterfaceBuilder

Ačkoli se ještě s aplikací InterfaceBuilder setkáme, a věnujeme jí a datům, jež zpracovává, samostatný díl, vyplatí se hned teď — prozatím bez nároku na úplnou přesnost — seznámit se s geniálním trikem, který Cocoa využívá (nejen) pro přípravu uživatelského rozhraní a jako podporu visuálního programování.

Základní myšlenka je vlastně jednoduchoučká: jestliže víceméně kterýkoli objekt může být persistentní (připomeňme čtvrtý díl seriálu, kde jsme rozebírali životnost objektů), můžeme přece síť objektů připravit ve vhodném editoru a uložit do souboru. Kdykoli pak aplikace tyto objekty potřebuje, soubor prostě načte — a je hotovo.

Konkrétně, představme si třeba jednoduchoučký dialog:

PB5

jeho součástí je objekt třídy NSPanel, který representuje okno, NSTextField obsahující textové pole, a dva NSButtony, representující tlačítka. Pomocí InterfaceBuilderu — který má samozřejmě přístup k týmž knihovnám standardních tříd, jako kterákoli jiná aplikace — prostě dialog sestavíme jako síť odpovídajících objektů, určíme jejich hodnoty (např. titulky tlačítek) a vzájemné vztahy (umístění objektů v panelu), a uložíme do souboru. Kdykoli pak aplikace bude chtít dialog zobrazit, soubor načte; tím získá okamžitě a bez jakýchkoli mezikroků všechny objekty, jež do něj byly uloženy; pošle pak jen objektu NSPanel zprávu "zobraz se v popředí", a je hotovo.

Na první pohled se to zdá být přesně to samé, jako použijeme-li v Mac OS nebo v Epocu "resource", v něm dialog popíšeme, a pak aplikace použije službu "otevřít dialog podle resource XYZ". Ve skutečnosti je zde několik hlubokých rozdílů; podrobně se na ně podíváme později, ale v zásadě jde o to, že pracujeme neustále s plnohodnotnými standardními objekty, takže např. lze objekty přímo v InterfaceBuilderu "spustit" a prakticky tak vyzkoušet uživatelské rozhraní dosud neexistující aplikace!

Nejzajímavější samozřejmě je otázka navázání prvků uživatelského rozhraní na "engine", na výkonné rutiny v aplikaci. Visuální prostředí ve Windows to obvykle řeší generováním zdrojového kódu; Java dokonce přináší komplikovaný a zhola zbytečný systém anonymních tříd... přitom je to v plně objektovém prostředí nesmírně jednoduché a efektivní: úplně stačí, jestliže dokážeme v editoru objektových sítí vytvářet vazby mezi objekty — včetně objektů z "engine".

Dejme tomu, že se rozhodneme dialog řídit z našeho vlastního objektu třídy DialogController, jejíž rozhraní je v Objective C definováno takto:

@interface DialogController:NSObject
{
  ...
  id text;
  ...
}
...
-void vykonat;
...
@end

Přímo v InterfaceBuilderu pak můžeme snadno určit takovou vazbu mezi objekty, jež zajistí, aby promònná text našeho objektu třídy DialogController obsahovala odkaz na objekt třídy NSTextField, jež v dialogu representuje textové pole. Je to jednoduché — prostě myší táhneme z objektu, representujícího DialogController, nad textové pole. InterfaceBuilder mezi nimi "natáhne drát", který representuje spojení, a v panelu inspektoru nám dá vybrat, kterou z proměnných objektu chceme nastavit (je jasné, že obecně jich bude objekt mít více než jednu):

PB6

Vlastní práce s textovým polem pak je triviální — chceme-li jej např. nastavit na hodnotu "Ahoj", použijeme prostě příkaz "[text setString:@"Ahoj"]"; podobně aktuální obsah textového pole můžeme kdykoli zjistit jako hodnotu výrazu "[text string]".

Malinko — ale opravdu jen malinko — složitější situace nastane při předávání "akcí", tj. činnosti uživatele, od objektů grafického uživatelského rozhraní "dovnitř" aplikace. Základní princip však zůstává úplně stejný: každý objekt, který může vyvolat nějakou akci (např. tlačítko nebo položka menu) obsahuje nejen odkaz na objekt, jemuž má o akci referovat, ale také jméno zprávy, již k tomu má použít. I mechanismus propojení objektů je téměř stejný:

PB7

Na minulém obrázku v InterfaceBuilderu určujeme, že tlačítko "OK" má při stisknutí odeslat zprávu "vykonat" našemu objektu třídy DialogController (jehož chování podle potřeby sami naprogramujeme). Tentokrát jsme "natáhli drát" od tlačítka na náš vlastní objekt, a v inspektoru naopak nevolíme proměnnou (ta je v levé části určena "natvrdo" a jmenuje se "target"), ale zprávu v části pravé — opět u skutečných objektů bude zpráv, jimž objekt rozumí, více, a my máme možnost vybrat kteroukoli z nich.

Tento systém nás ale samozřejmě neomezuje na objekty z "engine"! Stejně dobře můžeme určit, že tlačítko "Zavřít" má odeslat třeba zprávu "performClose" oknu, ve kterém je umístěno — pak bude možné tlačítkem okno zavřít. Zase jen "natáhneme drát" tak, jak chceme objekty spojit — v tomto případě tedy od tlačítka na okno — a zvolíme v inspektoru požadovanou zprávu:

PB8

Nebo třeba můžeme, chceme-li, tlačítko odeslat zprávu "terminate" standardnímu objektu, representujícímu aplikaci — stisknutí tlačítka pak aplikaci ukončí... systém nabízí téměř neomezenou flexibilitu.

Shrnutí

Víme již nejen jaké programy pro systém Cocoa psát; dnes jsme si ukázali i základní rysy aplikace ProjectBuilder, jež automatizuje celý proces tvorby aplikací, i principy vazby na InterfaceBuilder, který (mimo jiné) umožňuje připravovat grafické uživatelské rozhraní aplikace pomocí visuálního programování.

Ještě si tedy ukážeme ladění, a pak se již můžeme pustit do popisu konkrétních služeb ze standardních knihoven Cocoa: začneme samozřejmě "odspoda" — nejprve se seznámíme se základní knihovnou obecných služeb, nazvanou FoundationKit.


Zpět Obsah Další

Copyright © Chip, O. Čada 2000-2003