Pojmenované vlastnosti objektů: řazení jmen a agregační funkce - 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:

Soutěž

Sponzorem soutěže je:

IDIF

 

Odkud pochází fotografka Anne Erhard?

V dnešní soutěži hrajeme o:

Seriály

Více seriálů



Software

Pojmenované vlastnosti objektů: řazení jmen a agregační funkce

7. února 2006, 00.00 | Dnes si "na rozloučenou" s pojmenovanými vlastnostmi ukážeme několik rozšiřujících a velmi praktických služeb, které systém KVC v prostředí Cocoa nabízí: půjde o řazení jmen (key paths) a o speciální agregační služby.

V podstatě všechny zásadní informace o pojmenovaných vlastnostech objektů (key/value coding, KVC) a jeho využití v prostředí Cocoa jsme si již řekli: ukázali jsme si primární účel, jímž je umožnění abstraktních vazeb mezi zcela universální objekty grafického uživatelského rozhraní a atributy objektů v modelu; viděli jsme, že pro základní možnost využití KVC v zásadě není zapotřebí žádná práce navíc, jen musíme dodržet jednoduché konvence při pojmenovávání accesorů – a minule jsme si také ukázali, že při práci s relacemi 1:N (nebo chcete-li, atributy, jejichž hodnotou je pole či množina objektů) můžeme implementací speciálních accesorů podstatně zvýšit efektivitu.

Dnes si "na rozloučenou" s pojmenovanými vlastnostmi ukážeme několik rozšiřujících a velmi praktických služeb, které systém KVC v prostředí Cocoa nabízí: půjde o řazení jmen (key paths) a o speciální agregační služby.

Řazení jmen

Skutečné pohodlí přístupu k pojmenovaným vlastnostem objektů poznáme teprve ve chvíli, kdy začneme používat řazení jmen (key paths). O co vlastně jde? Inu, je to jednoduché: jestliže můžeme namísto volání metody používat její jméno, je jen logické, abychom namísto volání řady metod jedné za druhou použili "dlouhé" jméno, které se skládá ze složených jmen všech těchto metod.

Představme si situaci, kdy objekt kniha neobsahuje přímo jméno autora, ale namísto něj odkaz na objekt autor třídy Clovek, v níž máme k dispozici řadu atributů, počínaje textovými atributy vlastniJmeno a prijmeni přes atributy otec, matka, manzel, manzelka obsahující jiné objekty třídy Clovek, až třeba po atribut knihy, který obsahuje seznam všech knih – objektů třídy Kniha – které daný člověk napsal. Pak je zřejmé, že kupříkladu jméno tchyně autora naší knihy můžeme získat jako klasický výraz

[[[[kniha autor] manzelka] matka] vlastniJmeno]

Namísto toho můžeme alternativně v Cocoa využít řazení jmen, kdy nám týž výsledek dá jediná zpráva

[kniha valueForKeyPath:@"autor.manzelka.matka.vlastniJmeno"]

Nyní už začíná být sporné, zda náhodou není používání pojmenovaného přístupu šikovnější dokonce i při běžném programování – zvláště vezmeme-li v úvahu flexibilitu danou tím, že nemusíme přemýšlet o tom, co jsou accesory a co proměnné.

(Výhodou "klasického" přístupu s posíláním zpráv samozřejmě stále zůstává to, že překladač ověří, jsou-li jména zpráv známá, a pokud ne, ohlásí varování; uděláme-li naproti tomu překlep v "key path", dozvíme se o chybě až za běhu. Proto jsou samozřejmě všechny triky založené na pojmenovaných vlastnostech objektů ideální pro vazbu na GUI, ale méně praktické při běžném programování.)

Agregační funkce

Pokud "key paths" zahrnují i relace 1:N (v našem minulém příkladu tomu tak nebylo, všechny relace autor, manzelka, matka i vlastniJmeno byly typu 1:1), můžeme dokonce mezi jednotlivá jména relací vkládat speciální agregační funkce. Standardní knihovny Cocoa na jejich základě vyhodnotí a vrátí výsledek.

Dejme tomu, že se třeba pohybujeme v islámském světě, a tedy namísto relace 1:1 manzelka máme relaci 1:N manzelky. Pokud bychom chtěli zjistit, kolik má daný autor manželek, můžeme samozřejmě použít klasické cesty s výrazem [[autor manzelky] count], případně ekvivalentní [[autor valueForKey:@"manzelky"] count], jenže to se opět hodí pouze při psaní kódu, ale nikoli pro obecnou vazbu na objekty GUI: jak bychom leda měli specifikovat, že se počet má zobrazit v textovém poli? Řešením je použití agregační funkce @count v rámci pojmenovaných vlastností: [autor valueForKeyPath:@"manzelky.@count"].

Ukažme si jednoduchý příklad kompletního programu, který prakticky vyzkouší jak řazení jmen (v několika variantách), tak i různé agregační funkce. Základem je třída Model, jejíž instance mohou obsahovat vnořený objekt téže třídy v relaci 1:1 another a/nebo libovolné vnořené objekty v relaci 1:N foo. Pro přehlednost jsou objekty Model očíslovány (přidělením sériového čísla v metodě init) a tato čísla používáme při zobrazení:

@interface Model:NSObject {
    NSMutableSet *foo;
    Model *another;
    int serial;
}
+(Model*)model;
@end
@implementation Model
-init {
    if (!(self=[super init])) return nil;
    static int seed=1;
    serial=seed++;
    return self;
}
+(Model*)model {
    return [[[self alloc] init] autorelease];
}
@end

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    // vytvoříme kořenový objekt
    Model *x,*m=[Model model];
    // uložíme do něj vnořený objekt 'a' a do něj další vnořený objekt
    [m setValue:x=[Model model] forKey:@"another"];
    [x setValue:[Model model] forKey:@"another"];
    // zobrazíme sériová čísla s užitím key paths objektu 'm'
    NSLog(@"m %@, prvni klasicky %@ / key path %@, druhy key path %@",
          [m valueForKey:@"serial"], // m
          [[m valueForKey:@"another"] valueForKey:@"serial"], // a, klasika
          [m valueForKeyPath:@"another.serial"], // key path
          [m valueForKeyPath:@"another.another.serial"]);
    // další magie: množina vnořených objektů
    NSMutableSet *ms=[m mutableSetValueForKey:@"foo"];
    for (int i=0;i<6;i++) [ms addObject:[Model model]];
    // key path může vrátit seznam sériových čísel
    NSLog(@"seznam: %@",[m valueForKeyPath:@"foo.serial"]);
    // můžeme užívat i agregační funkce!
    NSLog(@"pocet %@, soucet %@, prumer %@",
          [m valueForKeyPath:@"al"],
          [m valueForKeyPath:@"al"],
          [m valueForKeyPath:@"al"]);
    // a můžeme agregovat množiny na více úrovních
    NSArray *a=[[m valueForKey:@"foo"] allObjects];
    [[a objectAtIndex:0] setValue:x=[Model model] forKey:@"another"];
    ms=[x mutableSetValueForKey:@"foo"];
    for (int i=0;i<3;i++) [ms addObject:[Model model]];
    [[a objectAtIndex:1] setValue:x=[Model model] forKey:@"another"];
    ms=[x mutableSetValueForKey:@"foo"];
    for (int i=0;i<2;i++) [ms addObject:[Model model]];
    NSLog(@"vnorene: %@",[m valueForKeyPath:@"al"]);
    
    [pool release];
    return 0;
}

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

Tématické zařazení:

 » Rubriky  » Informace  

 » Rubriky  » Agregator  

 » Rubriky  » Software  

Poslat článek

Nyní máte možnost poslat odkaz článku svým přátelům:

Váš e-mail:

(Není povinný)

E-mail adresáta:

Odkaz článku:

Vzkaz:

Kontrola:

Do spodního pole opište z obrázku 5 znaků:

Kód pro ověření

 

 

 

 

 

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

Uživatelské jméno:

Heslo: