Druhé Objective C: atributy a accesory - 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

Druhé Objective C: atributy a accesory

3. března 2008, 09.00 | V tomto dílu našeho seriálu, věnovaném rozšíření jazyka Objective C 2.0, si ukážeme nové služby pro deklaraci atributů objektů a generování accesorů.

V tomto díle našeho seriálu, věnovaném rozšíření jazyka Objective C 2.0, si ukážeme nové služby pro deklaraci atributů objektů a generování accesorů.

Ačkoli je pravda, že – jak jsme uvedli v předcházejících dílech – asi nejvýznamnější jednotlivou novinkou Objective C 2.0 je definitivní odstranění syndromu "fragile class", deklarace atributů objektů a generování accesorů se přinejmenším zpočátku daleko více projeví na kódu, který píšeme. To proto, že odstranění syndromu "fragile class" se týká pouze čtyřiašedesátibitového prostředí; naproti tomu služby pro deklaraci atributů objektů a generování accesorů můžeme využívat kdekoli (ačkoli, jak uvidíme zanedlouho, i ty ve čtyřiašedesátibitovém prostředí nabízejí více).

Deklarace atributů objektů

Atributy ("properties") objektu jsou ty jeho instanční proměnné, jež obsahují jeho význačné vlastnosti. Pokud bychom kupříkladu definovali třídu Programmer takto:

@interface Programmer:NSObject { // ObjC 1.0
@private
  NSString *name,*surname;
  NSArray *languages;
  unsigned iq;
}
-(NSString*)name; // jméno programátora
-(void)setName:(NSString*)name;
-(NSString*)surname; // jeho příjmení
-(void)setSurname:(NSString*)sname;
-(NSString*)displayName; // jméno i příjmení
-(NSArray*)languages; // programovací jazyky, jež ovládá
-(void)setLanguages:(NSArray*)languages;
-(unsigned)iq; // jeho inteligence, je-li jaká
-(void)setIq:(unsigned)iq;
@end

definovali jsme atributy "name", "surname", "displayName", "languages" a "iq" – ovšem stálo nás to spoustu zbytečné a mechanické práce; a co teprve implementace! K té se ovšem vrátíme až v příštím odstavci.

Objective C 2.0 nabízí formální prostředek, jak výše uvedené atributy deklarovat pohodlněji: direktivu @property, jež implicitně deklaruje obě zprávy atribut a setAtribut, a navíc umožní určit některé podrobnější informace: kupříkladu u atributů name a surname je zřejmé, že budeme v implementaci chtít využít zprávu copy; naopak u languages budeme (dejme tomu) preferovat přidržení atributu zprávou retain.

Ve čtyřiašedesátibitovém prostředí celá deklarace třídy bude vypadat prostě takto:

@interface Programmer:NSObject // ObjC 2.0, 64 bitů
@property (copy) NSString *name,*surname;
@property (readonly) NSString *displayName;
@property (retain) NSArray *languages;
@property unsigned iq;
@end

V prostředí dvaatřicetibitovém zůstávají deklarace @property přesně stejné; bohužel ještě navíc musíme zopakovat deklaraci instančních proměnných (tj. blok "{ ... }") v přesně stejné podobě, jak vypadal v Objective C 1.0 na prvém výpisu – ve dvaatřicetibitovém módu není technicky možné, aby si překladač instanční proměnné "domyslel sám":

@interface Programmer:NSObject { // ObjC 2.0, 32 bitů
@private
  NSString *name,*surname;
  NSArray *languages;
  unsigned iq;
}
@property (copy) NSString *name,*surname;
@property (readonly) NSString *displayName;
@property (retain) NSArray *languages;
@property unsigned iq;
@end

I tak je ovšem vidět, že (a) deklarace je mnohem jednodušší, (b) přináší více informací o jednotlivých atributech objektu: je zřejmé, že jméno a příjmení jsou kopírovány, kdežto pole languages je sdíleno.

V hlavičkovém souboru není nic jiného zapotřebí; při výše uvedených deklaracích je zcela validní a korektní zasílání zpráv např. takto:

Programmer *p=...;
[p setSurname:@"Meyer"];
[p setName:[p surname]];
NSLog(@"%@, židák frajer",[p displayName]);
[p setIq:[p iq]+5];
...

Objective C 2.0 nabízí prostředky pro zjednodušení i tohoto zápisu; to si však ukážeme až příště, neboť to s deklarací atributů a generováním accesorů nijak přímo nesouvisí.

Generování accesorů

Jestliže deklarace atributů byla v Objective C 1.0 nepříjemná, implementace accesorů byla vskutku noční můrou. Nebudeme si ji ani vypisovat celou, jen ukážeme, jak jednotlivé metody vypadají:

@implementation Programmer // ObjC 1.0
-(NSString*)name {
  return [[name retain] autorelease];
}
-(void)setName:(NSString*)new {
  if (new==name) return;
  [name release];
  name=[new copy];
}
... stejné dvě metody pro "surname" ...
-(NSString*)displayName {
  return [NSString stringWithFormat:@"%@ %@",
    [self name],[self surname]];
}
... "getter" pro languages stejný ...
... "setter" se liší jen použitím ...
... zprávy "retain" namísto "copy" ...
-(unsigned)iq {
  return iq;
}
-(void)setIq:(unsigned)new {
  iq=new;
}
@end

Zde nám Objective C 2.0 ušetří nejvíc práce – kompletní implementace, odpovídající výše uvedenému bezmála čtyřicetiřádkovému monstru pro pouhou čtveřici atributů, vypadá takto:

@implementation Programmer // ObjC 2.0
@synthesize name,surname,languages,iq;
-(NSString*)displayName {
  return [NSString stringWithFormat:@"%@ %@",
    [self name],[self surname]];
}
@end

Tentokrát jsme nic nevynechali – to je vše, co je zapotřebí. Direktiva @synthesize automaticky vygeneruje accesory pro všechny uvedené atributy; jelikož díky deklaracím již překladač ví, kdy použít retain, kdy copy a kdy – jako v případě atributu iq – není zapotřebí ani jedno a stačí prostě zkopírovat hodnotu, není již zapotřebí nic dalšího. Jen ovšem musíme explicitně naprogramovat odvozený atribut displayName (a proto také není v direktivě @synthesize uveden).

To mimochodem platí obecně; pokud bychom z nějakého důvodu chtěli třeba accesory name a setName: naprogramovat sami, prostě to uděláme a jméno atributu name neuvedeme v direktivě @synthesize.

Zcela privátní atributy

Ve čtyřiašedesátibitovém prostředí překladač dokáže potřebné instanční proměnné vytvořit sám, aniž by bylo zapotřebí je deklarovat. Je zřejmé, že tato možnost úzce souvisí právě s novou implementací, jež zajišťuje odstranění syndromu "fragile class": jeden a týž trik se stará o to, že podtřídám "nemusí nic být" do struktury instančních proměnných nadtřídy, i o to, že tyto proměnné může překladač vytvářet sám, aniž by bylo zapotřebí je explicitně deklarovat v @interface.

Důsledkem je to, že nyní již v @interface nemusíme uvádět ty atributy, jež slouží třídě pouze interně, vůbec! Nejvhodnější je využít k tomu "rozšíření třídy" – nepojmenovanou kategorii, s níž jsme se seznámili v minulém dílu.

Dejme tomu, že naše třída Programmer obsahuje navíc atributy / instanční proměnné lines a boss, jež obsahují počet programových řádků, které dotyčný dosud spáchal, a jméno jeho nadřízeného; tyto atributy však jsou z nějakých důvodů privátní a využívá jich pouze sama třída Programmer, případně několik málo tříd, jež s ní úzce spolupracují; ostatním však nemají být k dispozici.

V Objective C 1.0 (a také v Objective C 2.0 ve dvaatřicetibitovém prostředí) musíme i tyto instanční proměnné deklarovat v @interface; pouze jim odpovídající accesory můžeme deklarovat a definovat v neveřejné kategorii, případně v implementaci třídy samotné. Soubor "Programmer.h" s rozhraním tedy bude vypadat nějak takto:

@interface Programmer:NSObject { // ObjC 2.0, 32 bitů
@private
  NSString *name,*surname;
  NSArray *languages;
  unsigned iq;
  // interní použití
  unsigned lines;
  NSString *boss;
}
@property (copy) NSString *name,*surname;
@property (readonly) NSString *displayName;
@property (retain) NSArray *languages;
@property unsigned iq;
@end

Velmi nepříjemné je to jak z důvodů principiálních – nikomu "venku" není nic do toho, jaké používáme instanční proměnné pro privátní kód! – tak i z příčin ryze praktických. Pokud se totiž rozhodneme provést uvnitř implementace změnu, jež sice veřejné rozhraní nijak nenaruší, ale změní tyto privátní instanční proměnné – přidá-li k nim třeba ještě třetí – máme problém: veškerý kód, který by mohl obsahovat podtřídu Programmera, je nutné znovu přeložit!

V Objective C 2.0 ve čtyřiašedesátibitovém prostředí tomu je jinak. Soubor "Programmer.h" bude obsahovat stále jen zcela veřejné údaje z výpisu, označeného výše v tomto článku "@interface Programmer ... ObjC 2.0, 64 bitů". Implementační soubor "Programmer.m" pak bude obsahovat zhruba toto:

#import "Programmer.h"
// deklarace privátních atributů
@interface Programmer ()
@property (copy) NSString *boss;
@property unsigned lines;
@end
// implementace

@implementation Programmer
@synthesize name,surname,languages,iq,boss,lines;
...
@end

Pokud se potřebné privátní instanční proměnné jakkoli změní, díky tomu, že Objective C 2.0 nepodléhá syndromu "fragile class", nemáme naprosto žádný problém: jen v implementačním souboru doplníme či jakkoli změníme deklarace v rozšíření Programmer () a odpovídajícím způsobem upravíme implementaci; stačí pak přeložit tento jediný soubor a vše bude fungovat s jakýmkoli kódem, ať již třídu Programmer využívá libovolným způsobem.

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

Tématické zařazení:

 » Rubriky  » Informace  

 » Rubriky  » Agregator  

 » Rubriky  » Tipy a Triky  

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