NSTreeController - MujMAC.cz - Apple, Mac OS X, Apple iPod

Odběr fotomagazínu

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:

Seriály

Více seriálů



Software

NSTreeController

15. září 2006, 00.00 | Dnes se ještě na chvilku vrátíme k našemu poslednímu tématu, k controllerům: až dosud jsme probrali většinu základních služeb, ukázali jsme se vše možné – vyjma nejsložitějšího kontroléru, třídy NSTreeController. Jak už samotné jméno napovídá, tento kontrolér slouží pro representaci hierarchických modelů: hodil by se třeba pro systém složek a souborů, nebo zcela obecně pro jakýkoli model, jehož datové objekty se skládají do stromové struktury.

Minule jsme si v našem seriálu, věnovaném programování ve vývojové prostředí Cocoa, na chvilenku odskočili do budoucnosti – ukázali jsme si, co nás nejspíše čeká v Objective C 2.0 v Leopardu.

Dnes se ještě na chvilku vrátíme k našemu poslednímu tématu, k controllerům: až dosud jsme probrali většinu základních služeb, ukázali jsme se vše možné – vyjma nejsložitějšího kontroléru, třídy NSTreeController. Jak už samotné jméno napovídá, tento kontrolér slouží pro representaci hierarchických modelů: hodil by se třeba pro systém složek a souborů, nebo zcela obecně pro jakýkoli model, jehož datové objekty se skládají do stromové struktury.

Základy

Obecně je stromová struktura definována pouze dvojicí údajů:

  • kořenovým objektem celého stromu;
  • předpisem, který pro libovolný daný objekt (včetně kořenu) nalezne jeho podřízené.

Nejinak tomu je i s třídou NSTreeController: kořenový objekt (nebo objekty, k tomu se hned vrátíme) pro ni určíme týmž způsobem, jako objekt representovaný praobyčejným NSObjectControllerem – to již dávno známe. Jediné, co třída NSTreeController potřebuje navíc, je jméno zprávy, již můžeme poslat libovolnému datovému objektu, a jež vrátí jeho "děti". Toto jméno prostě nastavíme v inspektoru – a je to:

Takto nastavený NSTreeController – samozřejmě pod podmínkou, že jsme určili jeho kořenový objekt – můžeme hned používat jako řídící objekt pro libovolné objekty grafického uživatelského rozhraní, jež podporují odpovídající vazby; typicky se bude jednat o objekty tříd NSBrowser a NSOutlineView. Navážeme je (respektive, v případě NSOutlineView, samozřejmě spíše jeho sloupce) na atribut arrangedObjects kontroléru, v podstatě stejně, jako jsme to dělali nedávno u třídy NSArrayController. Stejně dobře samozřejmé můžeme navázat ostatní atributy (často určitě využijeme selection), jež fungují týmž způsobem, jako u všech kontrolérů.

A jak tomu je s možností specifikovat více kořenových objektů? Inu, to je jednoduché: v praxi se dost často stává, že jediný kořenový objekt (jímž by třeba v systému souborů mohl být "tento počítač") nechceme vůbec zobrazovat – na nejvyšší úrovni browseru nebo "outline view" tak má být objektů více (totiž právě ty, jež jsou "dětmi" skrytého objektu kořenového).

Třída NSTreeController tomuto požadavku elegantně vychází vstříc: jak její kořenový objekt totiž můžeme určit stejně dobře jeden jediný objekt (jako u NSObjectControlleru), jako pole (či množinu) – stejně, jako tomu bylo u NSArrayControlleru.

Pro větší efektivitu...

V naprosté většině případů výše popsané nastavení bohatě stačí: třída NSTreeController žádný jiný údaj, nežli odkaz na skupinu podřízených objektů nepotřebuje. Kontrolér samozřejmě musí znát i další údaje; ty však vždy může od skupiny podřízených objektů odvodit (kupříkladu, je-li tato skupina prázdná, objekt se zobrazí jako "list", tedy bez otevíracího trojúhelníčku; je-li neprázdná, objekt samozřejmě "trojúhelníček" bude mít, neboť jeho prostřednictvím lze přejít k objektům podřízeným).

V některých výjimečných případech (dočtěte také celý článek!) se však může stát, že faktické načtení a vrácení podřízených objektů je neefektivní. Proto třída NSTreeController umožňuje přímo zadat další dvě zprávy: "Count key" – je-li zadaná – vrací počet podřízených objektů; třída NSTreeController se v takovémto případě "obtěžuje" tyto objekty fakticky načíst pouze má-li je skutečně zobrazit a je-li jejich počet nenulový. Podobně můžeme definovat metodu "Leaf key", jež vrací booleovskou hodnotu podle toho, zda daný objekt má vůbec nějaké podřízené (a jen v tomto případě bude třída NSTreeController vůbec volat metody "Count key", resp. "Children key"), nebo ne.

Malý trik či dva...

Základní koncepce třídy NSTreeController je skvělá a uspoří nám spoustu práce s psaním "glue" kódu pro propojení modelu s grafickým uživatelským rozhraním, ostatně nejinak než všechny ostatní kontroléry. Nicméně, je třeba být trochu opatrný: bohužel, NSTreeController v Tygru je poněkud odfláknutý, jak implementačně, tak i designem – můžeme doufat, že v Leopardu to bude lepší.

Co se týká implementace, za některých (ne zcela jasně popsaných a poměrně výjimečných) podmínek může NSTreeController nekorektně uvolňovat své pomocné objekty, jejichž prostřednictvím spolupracuje s třídou NSBrowser. Nastane-li tato situace, podle zkušeností obvykle pomůže nastavit "Count key", ačkoli bychom jej nepotřebovali kvůli samotné efektivitě; klidně můžeme odpovídající metodu v objektu definovat přesně týmž způsobem, jakého by NSTreeController využil kdybychom ji nedefinovali vůbec:

-(unsigned)countKey {
  return [[self children] count];
}

Samozřejmě, že konkrétní jména metod mohou být odlišná – záleží na tom, co napíšeme do odpovídajících kolonek v Inspektoru.

Druhý problém souvisí s designem třídy. Nejprve malá vsuvka: dosud jsme si neukazovali, jak přesně vypadá rozhraní třídy NSOutlineView – jednotlivé řádky zde nejsou jednoznačně representovány číslem (neboť by to samozřejmě vzhledem k možnosti "otvírat" a "zavírat" podstromy nedávalo dobrý smysl), nýbrž obecným objektem, který se obvykle v API nazývá "item". Řídíme-li objekt třídy NSOutlineView prostřednictvím objektu NSTreeController, "itemy" se podle potřeby samozřejmě generují automaticky aniž bychom se o to museli starat; to je zcela v pořádku.

Problém však nastane ve chvíli, kdy chceme nějak zpracovávat objekty, k nimž se dostaneme prostřednictvím NSOutlineView – zcela typický příklad je drag&drop či metody delegáta. V takovém případě nám totiž NSOutlineView dá právě seznam "itemů" representujících objekty – a my na jejich základě potřebujeme nalézt tyto objekty, jenže obecně nevíme jak! "Itemy" jsou jakési interní pomocné objekty, generované třídou NSTreeController – a my o nich ani o jejich vztahu ke skutečným objektům modelu nic nevíme!

Naštěstí je poměrně snadné tento vztah "vyhackovat" z knihovních služeb, a flexibilita jazyka Objective C nám umožňuje si tuto službu doplnit. "Itemy" totiž ve skutečnosti nabízejí metodu, jejímž prostřednictvím se k objektu, jenž representují, můžeme dostat; jen se jaksi programátoři firmy Apple neobtěžovali tuto metodu publikovat. Snadno to ale doženeme deklarací

@interface NSObject (AppleInternalMethodAccess)
-observedObject;
@end

Nyní můžeme kterémukoli "itemu" poslat zprávu observedObject, a "item" nám vrátí objekt, jemuž odpovídá; tak třeba klasickou metodu delegáta třídy NSOutlineView, jenž ověří, zda je možné daný objekt editovat, můžeme implementovat takto – samozřejmě za předpokladu, že objekty našeho modelu mají metodu isEditable, jejíž pomocí můžeme zjistit zda daný objekt modelu lze měnit nebo ne:

-(BOOL)outlineView:(NSOutlineView*)ov shouldEditTableColumn:(NSTableColumn*)c item:item {
    return [[item observedObject] isEditable];
}

Samozřejmě, použijeme-li tento trik, musíme si dávat pozor na nové verse systému: může se kdykoli stát, že Apple vydá upgrade, v němž zpráva observedObject přestane fungovat (je to ale poměrně málo pravděpodobné, neboť zmíněný trik se užívá velmi široce).

Obsah seriálu (více o seriálu):

Tématické zařazení:

 » Rubriky  » Informace  

 » Rubriky  » Agregator  

 » Rubriky  » Začínáme s  

 » Rubriky  » Software  

 

 

 

Nejčtenější články
Nejlépe hodnocené články
Apple kurzy

 

Přihlášení k mému účtu

Uživatelské jméno:

Heslo: