Pojmenované vlastnosti objektů: implementace - 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ů



Informace

Pojmenované vlastnosti objektů: implementace

29. prosince 2005, 00.00 | V minulém dílu našeho seriálu jsme si na poněkud umělém příkladu s datovým zdrojem pro tabulku ukázali základní principy přístupu k pojmenovaným vlastnostem objektu. Dnes si řekneme něco více o tom, jak správně implementovat objekty pro datový model, aby s přístupem k pojmenovaným vlastnostem optimálně spolupracovaly.

V minulém dílu našeho seriálu jsme si na poněkud umělém příkladu s datovým zdrojem pro tabulku ukázali základní principy přístupu k pojmenovaným vlastnostem objektu. Víme, že libovolnému objektu můžeme poslat zprávu valueForKey:, jejímž argumentem je jméno atributu, a skutečně korektně hodnotu patřičného atributu dostaneme – bez ohledu na to, zda je uložena v proměnné objektu nebo zda k ní zajišťuje přístup accesor, a bez ohledu na to, jakého je typu. Podobně můžeme hodnoty nastavovat pomocí metody setValue:forKey:.

Dnes si řekneme něco více o tom, jak správně implementovat objekty pro datový model, aby s přístupem k pojmenovaným vlastnostem optimálně spolupracovaly.

Základní implementace: vůbec žádná práce...

Připomeneme-li si způsob, jakým knihovní kód při zpracování zpráv valueForKey: a setValue:forKey: funguje (jak jsme si jej popsali minule), je zřejmé, že pro jejich základní využití nemusíme dělat doslova nic: definujeme prostě proměnné a accesory, třeba takto

@interface Model:NSObject {
  int serial; // sériové číslo objektu
  NSString *title;
}
-(NSString*)title;
-(void)setTitle:(NSString*)tt;
-(NSString*)identification; // identifikace objektu
@end

s poměrně přirozenou implementací

@implementation Model
-init { // nastaví sériové číslo
  if (!(self=[super init])) return nil;
  static int seed=1;
  serial=seed++;
  return self;
}
-(void)dealloc {
  [self setTitle:nil];
  [super dealloc];
}
-(NSString*)title {
  return [[title retain] autorelease];
}
-(void)setTitle:(NSString*)tt {
  if (title==tt) return;
  [title release];
  title=[tt copy];
}
-(NSString*)identification {
  return [NSString stringWithFormat:@"%@ (%d)",title,serial];
}
@end

bude přístup k pojmenovaným vlastnostem fungovat korektně: je-li o objekt třídy Model, pak [o valueForKey:@"title"] vrátí titulek prostřednictvím acccesoru title, [o valueForKey:@"identification"] vrátí generovanou identifikaci prostřednictvím metody identification (jež je vlastně nepravým accesorem) a [o valueForKey:@"serial"] vrátí sériové číslo, načtené přímo z proměnné. Můžeme také měnit titulek příkazem [o setValue:@"Whatever" forKey:@"title"] (a zavolá se korektně metoda setTitle:) či sériové číslo příkazem [o setValue:[NSNumber numberWithInt:nn] forKey:@"serial"]. Pokus zavolat [o setValue:@"whatever" forKey:@"identification"] by ovšem vedl k chybě.

Vidíme, že díky systému KVC máme "automaticky a zadarmo" hotovou podporu pro vazbu mezi objektem a GUI – je zřejmé, že můžeme např. v GUI nastavit textové pole, pro nějž pouze určíme, že representuje "title" nějakého objektu; textové pole pak zjistí, jakou hodnotu má zobrazovat, tak, že objektu pošle zprávu valueForKey:@"title", a pokud obsah textového pole změníme, předá změnu modelu pomocí zprávy setValue:nováHodnota forKey:@"title".

Jmenné konvence

Jak je zřejmé z popisu funkce metod valueForKey: a setValue:forKey:, musíme si při psaní accesorů dát pozor na to, abychom dodrželi jmenné konvence. Výše uvedené accessory jsou tedy v pořádku; stejně dobře bychom mohli implementovat také accesory

-(BOOL)isSpecial { ... }
-(void)setSpecial:(BOOL)special { ... }

a vše by stále fungovalo zcela korektně. Pokud bychom však jmenné konvence nedodrželi a užili nestandardní kombinaci accesorů, třeba

-(NSString*)name { ... }
-(void)useName:(NSString*)name { ... } // špatné jméno!

systém KVC by nefungoval – zatímco [o valueForKey:@"name"] by bylo v pořádku, [o setValue:.. forKey:@"name"] (stejně jako [o setValue:... forKey:@"useName"]) by jen ohlásilo chybu.

Pomocné metody pro speciální případy

V praxi může nastat jeden speciální případ, s nímž si standardně metody KVC nemohou dost dobře poradit: co se má stát, pokud se pokusíme nastavit hodnotu proměnné serial na nil příkazem [o setValue:nil forKey:@"serial"]? Nula to není – to by vypadalo jinak: [o setValue:[NSNumber numberWithInt:0] forKey:@"serial"]. Tuto situaci nelze řešit automaticky, neboť systém nemůže vědět, jak se s hodnotou nil chceme optimálně vyrovnat v případě konkrétního atributu; proto za normálních okolností, kdykoli se pokusíme nastavit hodnotu nil pro neobjektový atribut, knihovní kód ohlásí výjimku.

Můžeme tomu však snadno zamezit – stačí implementovat metodu setNilValueForKey:; knihovní kód ji pak automaticky zavolá, a v její implementaci můžeme udělat cokoli, co je třeba – kupříkladu takto:

-(void)setNilValueForKey:(NSString*)key {
  if ([key isEqualToString:@"serial"])
    [self setValue:[NSNumber numberWithInt:0] toKey:key];
  [super setNilValueForKey:key]; // vyvolá výjimku
}

Druhým speciálním případem může být situace, kdy z nějakého důvodu nechceme, aby systém KVC přistupoval přímo k proměnným objektu (např. proto, že vyžadujeme "striktní" zapouzdření, neboť vnitřní implementace objektu se bude často měnit, nebo proto, že využíváme zástupných objektů). Pak implementujeme metodu třídy accessInstanceVariablesDirectly, jež vrátí hodnotu NO; systém KVC pak bude proměnné ignorovat, a pokusíme-li se jej použít pro přístup k atributu, jenž nemá vlastní accesor (např. tedy serial), dojde k chybě.

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

Tématické zařazení:

 » Rubriky  » Informace  

 » Rubriky  » Agregator  

 » 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: