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:
Software
Začínáme s AppKitem
15. srpna 2005, 00.00 | Dnešním dílem našeho seriálu, věnovaného vývojovému prostředí Cocoa, se začneme zabývat programováním plnohodnotných aplikací s využitím objektové knihovny AppKit.
Dnešním dílem našeho seriálu, věnovaného vývojovému prostředí Cocoa, se začneme zabývat programováním plnohodnotných aplikací s využitím objektové knihovny AppKit (a také, v souvislosti s datovým modelem aplikací – viz. níže – si toho řekneme trochu více o jednom z nejnovějších subsystémů Cocoa, o Core Data). Knihovna AppKit nabízí třídy, funkce a další služby podobně, jako Foundation Kit, který již známe; zatímco Foundation obsahoval obecné třídy, vhodné pro libovolný program, v AppKitu jsou soustředěny třídy a služby potřebné právě pro plnohodnotné aplikace Mac OS X.
Aplikace je program, který nabízí standardní grafické uživatelské rozhraní, založené na oknech, nabídkách, myši a dalších prvcích rozhraní systému Mac OS X. Kromě toho aplikace musí dodržovat řadu systémových konvencí: obvykle podporuje služby typu schránky či Services, typicky nabízí standardní práci se soubory včetně služeb drag&drop, řada aplikací využívá standardní systém práce s dokumenty (včetně přiřazení typů dokumentů aplikaci) a podobně.
Všechny tyto služby zajišťují odpovídající třídy AppKitu. Vývojové prostředí Xcode navíc obsahuje standardní templates, díky nimž pro vytvoření základní aplikace, jež korektně dodržuje všechny konvence, nemusíme dělat téměř nic: třídy jsou automaticky sestaveny tak, jak je pro jednoduchou aplikaci zapotřebí, a Xcode nám vygeneruje i základní nejjednodušší grafické uživatelské rozhraní.
MVC
Dříve, než se pustíme do konkrétních služeb a tříd knihovny AppKit, je vhodné se trochu blíž věnovat obecné struktuře dobře navržené objektové aplikace: třídy a služby AppKitu totiž právě z této struktury vycházejí, a budeme-li jí rozumět a mít ji na paměti, budeme se v AppKitu (který je samozřejmě o dost složitější, než knihovna Foundation) lépe orientovat. Dnešní díl proto věnujeme obecným pravidlům objektového aplikačního designu typu "Model, View, Controller".
Jde o to, že základem kvalitního objektového designu je rozdělení aplikace na tři přinejmenším logicky nezávislé moduly: ty se tradičně nazývají "model" (representace dat, jež aplikace zpracovává), "view" (uživatelské rozhraní aplikace) a "controller" (správce, který váže "model" a "view" dohromady); pro aplikační strukturu, založenou na těchto třech modulech, se často používá zkratka složená z jejich prvních písmen: MVC.
Každý z modulů má jasně stanovenou úlohu:
- Model representuje data, nad nimiž aplikace pracuje: obrázek, film, textový dokument, databázi (nebo, v tomto případě zvlášť vhodně pojmenovaný, databázový model), strukturu čísel a formulí pro spreadsheet... Aplikace samozřejmě může obsahovat modelů více, v závislosti na tom, s kolika "datovými bloky" pracuje;
- View je pohled na model, který nabízí grafické uživatelské rozhraní. Podstatné a důležité z hlediska dobře navržené struktury aplikace je to, že samo grafické rozhraní neobsahuje ani vlastní data (to je úkolem modelu), ani logiku práce s nimi (o to se, jak hned uvidíme, stará Controller). Jednou z nejběžnějších a nejčastěji opakovaných chyb, při objektovém návrhu, jsou právě "views", obsahující data či řídící rutiny: tato chyba bývá běžná zvláště v prostředích, založených na C++. Modulů view (z nichž každý je samozřejmě obecně složen z řady objektů) může být v aplikaci obecně také více, neboť někdy zobrazujeme více různých údajů o modelu zároveň;
- Controller stojí mezi modelem a "view", a zajišťuje logiku chování celého systému. Controller přijímá události, vyvolané vstupními objekty v rámci "view" (např. nabídkami, tlačítky a podobně); zpracuje je podle potřeby, a pak odpovídajícím způsobem upraví výstupní objekty v rámci "view" (textová pole, tabulky a další). Přitom samozřejmě podle potřeby spolupracuje s modelem — předává mu požadavky na změny, a kdykoli je to zapotřebí, vyžádá si od něj údaje pro zobrazení. V jednoduchých aplikacích bývá jeden controller, který "řídí vše"; v aplikacích, jež pracují s více nezávislými dokumenty, je obvykle jeden controller pro každý dokument. Složitější aplikace mohou mít controllerů řadu, každý z nich specializovaný na jinou část celkové funkčnosti.
Celou strukturu ilustruje následující obrázek:
Při návrhu, založeném na struktuře MVC, získáme nejvyšší flexibilitu a vícenásobnou použitelnost kódu: model není nijak závislý na konkrétní aplikační logice, můžeme jej beze změny a snadno využít v jakékoli jiné aplikaci, jež pracuje se shodnými daty. Podobně controller nijak nezávisí na konkrétním vzhledu grafického uživatelského rozhraní — to tak můžeme podle potřeby (a podle požadavků zákazníků) snadno měnit, aniž bychom museli zasahovat do kódu controlleru (natož pak modelu).
Triviální příklad
Pro lepší ilustraci si ukažme postavení jednotlivých objektů v hypotetické aplikaci, jež nedokáže nic jiného, nežli uchovat jediný textový řetězec (příště si ukážeme kompletní a mnohem dokonalejší aplikaci; dnes jde pouze o koncepci).
Model
Kód modelu bude zajišťovat načtení dat z nějakého vhodného místa pro permanentní uložení (dejme tomu, že aplikace používá defaults databázi); pro vyšší vrstvy pak nabídne triviální dvojici metod string a setString:, jež získají momentální hodnotu řetězce:
// model -(NSString*)string { return [[NSUserDefaults sharedUserDefaults] stringForKey:@"string"]; } -(void)setString:(NSString*)string { [[NSUserDefaults sharedUserDefaults] setObject:string forKey:@"string"]; }
To je celé. Model je za normálních okolností "pasivní", sám od sebe nic nedělá – jakékoli operace nad ním jsou vyvolány prostřednictvím zpráv, odeslaných z controlleru.
(Úmyslně na této úrovni zatím neřešíme, v rámci jaké třídy by byl kód modelu umístěn, a kde se vezme její instance: u takto triviální aplikace by totiž bylo nejrozumnější, aby model sdílel kód s controllerem, ovšem v obecném případě to samozřejmě dobře není. Praktičtější příklad si ukážeme příště.)
View
Objekty view, tedy grafického uživatelského rozhraní, jsou téměř vždy umístěny v souborech NIB, vytvářených a editovaných prostřednictvím aplikace InterfaceBuilder – my jsme se s ní již seznámili v minulých dílech, a v rámci popisu knihovny AppKit si o ní řekneme mnohem více.
Na této úrovni však stačí říci, že celým grafickým uživatelským rozhraním pro naši triviální aplikaci může být jediné okno, obsahující jediný objekt typu "textfield", zpřístupněný prostřednictvím "outletu" text. Není třeba vůbec nic programovat.
Controller
Kompletní controller bychom mohli také vytvořit bez jakéhokoli programování s využitím systému bindings (a v budoucích dílech to tak také budeme dělat); dnes si však ukážeme, jak by vypadal jeho kód v Objective C – jen proto, aby bylo zřejmé, co je přesně úkolem controlleru.
Je to, samozřejmě, velmi jednoduché – náš controller bychom umístili také do NIBu, a naprogramovali bychom v něm dvě metody (předpokládejme, že model je k dispozici v rámci proměnné model; jinak viz také poznámku na konci odstavce "Model"):
// controller -(void)awakeFromNib { [text setStringValue:[model string]]; } -(IBAction)textChanged:sender { [model setString:[text stringValue]]; }
To je celé: standardní metoda awakeFromNib zajistí, aby se po spuštění aplikaci zobrazila v textovém poli správná hodnota. Akce textChanged: – již samozřejmě v NIBu navážeme na "target" textového pole, aby ji systém po změně hodnoty v textovém poli automaticky zavolal – pak zajistí uložení nové hodnoty do modelu.
Postavení controlleru snad je tedy zřejmé: důležité je právě to, že textové pole i model nejsou nijak přímo spojeny, ale že tuto vazbu mezi zcela obecným textovým polem (jež lze použít na spoustu jiných věcí), a mezi zcela obecným datovým modelem (který může být zobrazen mnoha jinými způsoby) zajišťuje samostatný controller. Lze si třeba zajisté představit, že bychom naprogramovali podtřídu třídy NSTextField, a tak vytvořili textové pole, specializované jen a jen na zobrazování a editaci hodnoty "string" z modelu; to je ale právě špatný objektový design...
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