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:

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

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  

Diskuse k článku

 

Vložit nový příspěvek   Sbalit příspěvky

 

property a KVC + KVO

Autor: mb Muž

Založeno: 03.03.2008, 09:52
Odpovědí: 0

Dobreho dne,

zajimalo by me, zda ma deklarace atributu pomoci @property nejake implementacni dusledky pro KVC a KVO. Z hlediska chovani samozrejme zadne zmeny neocekavam, spise bych ocekaval, ze budou zminene dve techniky pri pouziti @property nejakym zpusobem optimalizovany. Mate o tomto nejake informace? Prip. nejakou jinou pikantnost z "interni kuchyne" Applu?
Predem diky.

Odpovědět na příspěvek

RE: property a KVC + KVO

Autor: OC Muž

Založeno: 03.03.2008, 21:18

Vydržte prosím, momentálně naprosto nestíhám. Pokud nenapíši rozumnou odpověď tak cca do týdne, připomeňte se mi, prosím.

Někde v archivu bych měl mít odkaz na zkoumání rychlosti starého/nového překladače (to by nakonec mohlo jít i vygooglit, byl to nějaký z blogů zabývajících se apple). A bohužel také dvě chyby v novém překladači, na něž jsem sám narazil; jedna je drobnost týkající se hlášení warningů, ale druhá může zapříčinit crash :( :( :(

Odpovědět na příspěvek

RE: RE: property a KVC + KVO

Autor: mb Muž

Založeno: 04.03.2008, 17:36

Ja nasel jen nasledujici, ale to jste asi na mysli nemel... kazdopadne i tak je to zajimave cteni:

http://www.mike
ash.com/?page=pyblog/perf
ormance-comparisons-of-co
mmon-operations-leopard-e
dition.html

Odpovědět na příspěvek

RE: RE: RE: property a KVC + KVO

Autor: OC Muž

Založeno: 05.03.2008, 03:17

Ano, to jsem měl na mysli.

Tady jsou ty chyby v překladači -- snad se to zobrazí aspoň trochu použitelně, mujmac bohužel nemá náhled...

Warning: za určitých (ne zcela jasných) okolností překladač považuje typy, jež jsou stejně velké, za ekvivalentní:

208 /tmp> #import
typedef struct { float f; } Foo;
@interface X:NSObject
-(Foo)whatthe
h;
@end
@interface Y:NSObject
-(float)whatt
heh;
@end
void foo(id x) {
NSLog(@"%d",[x whattheh]);
}
209 /tmp> cc -Wall -framework Cocoa q.m
Undefined symbols:
// ie. no report at all, which supports the sizeof idea, but see below

210 /tmp> #import
typedef struct { double f; } Foo;
@interface X:NSObject
-(Foo)whatthe
h;
@end
@interface Y:NSObject
-(double)what
theh;
@end
void foo(id x) {
NSLog(@"%d",[x whattheh]);
}
211 /tmp> cc -Wall -framework Cocoa q.m
q.m: In function 'foo':
q.m:10: warning: multiple methods named '-whattheh' found
q.m:4: warning: using '-(Foo)whattheh'
q.m:7: warning: also found '-(double)whattheh'

Cr
ash: to je horší, nějak se jim tam ty generované properties vzájemně perou :(

36 /tmp> >crash.m
#import

@inter
face Base:NSObject
@property int whatever;
@end
@interfa
ce Oops:Base
@property (retain) id oops;
@end

@implement
ation Base
@synthesize whatever;
@end
@impleme
ntation Oops
@synthesize oops;
-(void)whatthe {
NSLog(@"1. %x",self.oops);
self.whatever=1;
NSLog(@"2. %x",self.oops);
}
@end



int main(int ac,char **av) {
[NSAutoreleasePool new];
[[Oops new] whatthe];
return 0;
}
37 /tmp> cc -Wall -framework Cocoa crash.m -arch x86_64 && ./a.out
2008-03-05 03:06:38.676 a.out[4233:10b] 1. 0
zsh: segmentation fault ./a.out
38 /tmp>

Odpovědět na příspěvek

RE: RE: RE: RE: property a KVC + KVO

Autor: OC Muž

Založeno: 05.03.2008, 03:19

Jo, pardon, k tomu warningu jsem poslal jen "pokročilý" příklad, ale zapomněl jsem na elementární:

38 /tmp> >warn.m
#import

@inter
face Y
-m1:(float)arg;
-m2:(
double)arg;
-m3:(double)
arg;
@end

@interface X
-m1:(int32_t)arg;
-m2
:(int64_t)arg;
-m3:(int3
2_t)arg;
@end

int main() {
[(id)0 m1:1]; // should warn, but doesn't
[(id)0 m2:1]; // should warn, but doesn't
[(id)0 m3:1]; // warns correctly
return 0;
}
39 /tmp> cc -Wall -framework Cocoa warn.m
warn.m: In function 'main':
warn.m:18: warning: multiple methods named '-m3:' found
warn.m:6: warning: using '-(id)m3:(double)arg'
wa
rn.m:12: warning: also found '-(id)m3:(int32_t)arg'
4
0 /tmp>

Odpovědět na příspěvek

 

 

Vložit nový příspěvek

Jméno:

Pohlaví:

,

E-mail:

Předmět:

Příspěvek:

 

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: