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
Mírná vylepšení v mezích zákona
30. srpna 2006, 00.00 | Dnes se ještě k projektu vrátíme s trochou různých vylepšení, na nichž si ukážeme další možnosti, jež nám systém vazeb Cocoa nabízí.
Minule jsme od našeho projektu trošku odbočili, povídajíce si o převodnících hodnot, přepínačích, jež podrobněji určují způsob, kterým se daná vazba bude interpretovat, a o využití zástupných hodnot ("placeholders").
Dnes se ještě k projektu vrátíme s trochou různých vylepšení, na nichž si ukážeme další možnosti, jež nám systém vazeb Cocoa nabízí.
Ukládání a obnovení dat
Ne však hned v prvém odstavci – začneme něčím, co nemá s vazbami zhola nic společného.
Pokud sami průběžně ve vlastním projektu zkoušíte to, o čem si zde povídáme, asi jste si také uvědomili, že ve chvíli kdy díky použití NSArrayControlleru začalo být možné, aby náš model obsahoval libovolně mnoho datových objektů, začalo být po čertech nepříjemné, že s každým ukončením aplikace o všechna vložená data přijdeme.
Škoda, že nepoužíváme objektů z frameworku Core Data; v takovém případě bychom měli persistenci docela a úplně "zadarmo" – jenže se nemůžeme učit příliš mnoho věcí naráz, abychom v tom neměli zmatek, takže datové modelování systému Core Data si ponecháme na později. I tak je ale pomoc velmi snadná: už dávno jsme si v třiatřicátém dílu našeho seriálu ukázali, jaké služby nabízí Foundation Kit pro persistenci objektů; stačí tedy bohatě, přidáme-li do naší modelové třídy dvojici metod
-initWithCoder:(NSCoder*)coder { if (!(self=[super init])) return nil; [self setWidth:[coder decodeFloatForKey:@"Width"]]; [self setFullName:[coder decodeObjectForKey:@"FullName"]]; return self; } -(void)encodeWithCoder:(NSCoder*)coder { [coder encodeFloat:width forKey:@"Width"]; [coder encodeObject:[self fullName] forKey:@"FullName"]; }
a hned můžeme model ukládat. Jen... musíme ještě někam přidat službu, jež toto uložení (a znovunačtení) vyvolá; mohli bychom sice změnit strukturu aplikace na práci s dokumenty, kdy bychom opět (nejen) tuto službu dostali "zadarmo", jenže zase – nyní se učíme práci s vazbami, a nikoli práci s třídami NSDocument a spol... takže to uděláme postaru a ručně: datový kontrolér rozšíříme o vlastní služby, konkrétně o ukládání a načítání dat.
Ono je to nakonec dobře, neboť v produkčním kódu velmi často užíváme vlastních datových kontrolérů, jejichž služby jsou tak či onak oproti základním třídám AppKitu obohaceny; alespoň si tedy vyzkoušíme, jak se to dělá:
- do aplikace přidáme soubor "Controller.h", obsahující rozhraní třídy Controller, jež je dědicem třídy NSArrayController s jednou akcí save:, a soubor "Controller.m", obsahující jeho implementaci (na tu se podíváme za chvilinku);
- soubor "Controller.h" vhodíme do okna NIBu; Interface Builder se tak dozví o existenci třídy Controller;
- a hned v Interface Builderu prostřednictvím inspektoru "Custom Class" určíme, že kontrolér bude objektem naší nové třídy:
Zatímco pro zásadní změnu typu kontroléru z třídy NSObjectController na třídu NSArrayController tento inspektor nestačil, právě pro takové věci, jako určení naší vlastní třídy, je určen, a funguje při nich výtečně.
Díky této změně již nyní Interface Builder "ví", že náš kontrolér nabízí akci save:; můžeme tedy na ni hned připojit položku "Save" z hlavní nabídky, a můžeme třeba do okna pro větší pohodlí ještě přidat nové tlačítko "Save" a připojit jej k akci také (jde o staré dobré spojování objektů GUI s akcemi v rámci paradigmatu action/target, jež již dávno důvěrně známe – jakkoli je zajímavé si uvědomit, že jiná vývojové prostředí, kupříkladu ta založená na Javě, dodnes nezvládají ani to!)
Pak již jen vytvoříme vhodnou implementaci – je skutečně jen na pár řádků, a mohla by vypadat třeba takto:
@implementation Controller -(NSString*)dataFilename { return @"/tmp/KVOTest.data"; } -(IBAction)save:sender { [NSKeyedArchiver archiveRootObject:[self content] toFile:[self dataFilename]]; } -(void)awakeFromNib { NSArray *a=[NSKeyedUnarchiver unarchiveObjectWithFile:[self dataFilename]]; if (a) [self setContent:a]; } @end
Snad to jediné, co stojí za samostatnou zmínku, je použití metody setContent: – my se již o ní zmínili jako o jedné z možností, kterak kontroléru dodat jeho obsah, a přesně to zde také děláme.
Chceme-li, můžeme se také konečně zbavit ošklivé registrace převodníku "MultiplyingTransformer" v jeho metodě load a přenést ji do metody initialize nového kontroléru, kam patří daleko spíše (ačkoli vůbec nejlépe by jí bylo v metodě initialize aplikačního kontroléru – ten však v naší triviální ukázkové aplikaci vůbec nemáme).
Filtrování zobrazených objektů
Poměrně běžná služba, již nabízejí aplikace s "tabulkovým" pohledem na množství datových objektů modelu, je možnost filtrovat zobrazená data – něco jako "ukaž mi pouze objekty, jejichž atribut 'firstname' obsahuje 'Jan'". Pojďme si tuto službu naprogramovat... eh, špatný výraz: díky tomu, že užíváme systém vazeb Cocoa a jeho kontroléry, pojďme si tuto službu během pár minut "namyšovat".
Otevřeme opět soubor "MainMenu.nib" v Interface Builderu, a na vhodné místo do okna vhodíme z palety "Cocoa–Text" vyhledávací textové pole NSSearchField – je tam docela vpravo dole. Pak je navážeme na náš kontrolér, a určíme možné vyhledávací predikáty; zvolíme třeba dva predikáty (stejně jako tomu bylo s vazbami typu "enable..." či s formátovanými textovými řetězci, může jich být libovolně mnoho).
Prvý predikát pojmenujeme "Full Name" a nastavíme jeho obsah na "fullName contains[c] $value" – jinými slovy, právě jsme řekli, že tento predikát má vybrat všechny datové objekty modelu, jejichž atribut "fullName" obsahuje textový řetězec, zapsaný do vyhledávacího pole (to je "$value"), a to bez ohledu na velikost písmen (to je "[c]") – jistě, predikáty jako takové jsme "zatím nebrali", takže to berte jako fakt; všechny možnosti, jež pro takovéto vyhledávání v Cocoa máme, si ukážeme později, až se budeme podrobně zabývat třídou NSPredicate a jejími možnostmi. Určení tohoto predikátu vypadá nějak takto:
Přidáme třeba ještě jeden predikát, nazvaný "Surname" a s nastavením "surname contains[c] $value" – ten nám umožní alternativně vyhledávat jen v samotném příjmení. A... a už nic. Můžeme aplikaci zbuildovat, spustit, a kochat se tím, jak nám NSArrayController pěkně filtruje datové objekty...
Počet objektů
Možná by ale ještě bylo příjemné, kdyby nám aplikace – obzvlášť vzhledem k čerstvě přidané možnosti filtrování – zobrazovala, kolik objektů je vlastně k dispozici, kolik z nich se právě vzhledem k platnému filtru zobrazuje, a třeba také kolik jich máme vybraných.
I to je ale díky vazbám kromobyčejně snadné: pozorní čtenáři možná ještě nezapomněli na padesátý sedmý díl našeho seriálu, v němž jsme se naučili využívat speciální atribut "@count" (a další) pro pole objektů v rámci KVC. Tehdy jsme atributy zadávali přímo v programu; to sice je možné, ale samozřejmě že původně jsou tyto služby určeny právě pro pohodlné nastavení vazby mezi objekty GUI a modelem bez jakéhokoli programování – a to si dnes nakonec ukážeme.
Na vhodné místo do okna přidáme obyčejné needitovatelné textové pole – třeba nad tabulku vedle vyhledávacího NSSearchFieldu – a abychom si vyzkoušeli speciální atributy polí (a zároveň také zástupné hodnoty, o nichž jsme si povídali minule), zobrazíme nejen počet všech, filtrovaných a vybraných objektů, ale také minimální, průměrnou a maximální šířku a výšku ze všech vybraných.
Je to jen chvilinka: pro textové pole samozřejmě použijeme mnohonásobnou vazbu "displayPatternValue"; její formátový řetězec nastavíme na
%{value1}@ selected of %{value2}@ (%{value3}@), width: %{value4}@ ≦ %{value5}@ ≦ %{value6}@, height: %{value7}@ ≦ %{value8}@ ≦ %{value9}@
a odpovídající vazby budou postupně od první po devátou
- "selectedObjects.@count" – počet právě vybraných objektů (vida, zde se nám právě hodí atribut "selectedObjects" namísto jinak mnohem častěji využívaného atributu "selection");
- "arrangedObjects.@count" – počet všech zobrazených objektů (v závislosti na právě platném filtrování);
- "content.@count" – počet všech objektů bez ohledu na filtr;
- "h" – minimální šířka ze všech vybraných objektů; nastavíme také "placeholdery" (alespoň ten "Null") na nulu – to proto, aby se zobrazilo něco rozumného i v případě, kdy žádný objekt vybraný není. Mimochodem, kdybychom zde užili vazby "h", fungovalo by to také – ale využití "selection" je efektivnější, zvláště v případě, že datových objektů je mnoho;
- zbývající vazby nastavíme analogicky na "h", @"selection.max.width", "ht", "ht" a "ht".
A teď je to již opravdu vše – aplikace kompletně funguje:
Snad jen drobnost; zjistíme, že pokud spočtený průměr vychází jako desetinné číslo o mnoha platných místech, zobrazí se s mnoha ciframi také v GUI – což patrně není zrovna to, co chceme. Pozorným čtenářům však je řešení jasné: prostě si napíšeme jednoduchý převodník hodnot ("value transformer"), který čísla podle potřeby zaokrouhlí, a v odpovídajících vazbách jej použijeme – to si můžeme nechat jako jednoduché cvičení...
Pokud by se snad někomu nedařilo, hotový projekt obsahující všechny popsané služby nalezne na www.ocs.cz/apps/KVOTest3.zip.
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