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:
Software
Validace hodnot
14. června 2006, 00.00 | Dnes si ukážeme další velmi důležitou techniku, jež sice v zásadě patří do KVC, ale prakticky použitelná a významná se stává právě až ve chvíli, kdy modelové objekty podporující KVC začneme používat prostřednictvím vazeb spolu se standardními objekty grafického uživatelského rozhraní Cocoa – proto jsme se o ní ostatně nezmínili dříve. Jedná se o systém automatických validací hodnot atributů.
Minule jsme se naučili implementovat – a prostřednictvím vazeb používat – převodníky hodnot. Dnes si ukážeme další velmi důležitou techniku, jež sice v zásadě patří do KVC, ale prakticky použitelná a významná se stává právě až ve chvíli, kdy modelové objekty podporující KVC začneme používat prostřednictvím vazeb spolu se standardními objekty grafického uživatelského rozhraní Cocoa – proto jsme se o ní ostatně nezmínili dříve. Jedná se o systém automatických validací hodnot atributů.
Nejprve přidáme do modelu text
Vrátíme se k předposlednímu příkladu atributů, který jsme si ukázali v textech, objasňujících mechanismus a funkci KVO – totiž k atributům firstname, surname a fullName – a přidáme je do modelu; použijeme poslední implementaci z onoho příkladu – do rozhraní naší modelové třídy Test tedy přidáme deklarace proměnných firstname a surname, takže rozhraní nyní bude vypadat takto:
@interface Test:NSObject { float width,height; NSString *firstname,*surname; } @end
Do rozhraní vedle již existujících metod setWidth: a setHeight: přidáme nově následující metody, převzaté z příkladu:
@implementation Test ... -(void)setFirstname:(NSString*)name { [firstname autorelease]; firstname=[[name capitalizedString] retain]; } -(NSString*)fullName { return [NSString stringWithFormat:@"%@ %@",firstname,surname]; } -(void)setFullName:(NSString*)name { NSArray *a=[name componentsSeparatedByString:@" "]; [self setFirstname:[a objectAtIndex:0]]; [self setValue:[a lastObject] forKey:@"surname"]; }
+(void)initialize { [self setKeys: [NSArray arrayWithObjects:@"firstname",@"surname",nil] triggerChangeNotificationsForDependentKey:@"fullName"]; } @end
V Interface Builderu pak přidáme do okna třeba ještě jeden formulář, s přidržením přepínače Alt jej zvětšíme na tři řádky, vhodně upravíme jejich titulky, a navážeme je postupně jejich vazbou "value" na všechny tři nové textové atributy, tedy na firstname, surname a na fullName – konkrétní postup si už snad na snímcích obrazovky ukazovat nemusíme, neboť je zřejmý.
Jenže nám to nefunguje tak úplně...
Když aplikaci přeložíme a vyzkoušíme, zjistíme, že víceméně vše funguje, jak má – můžeme vkládat nezávisle na sobě jména a korektně se generuje plné jméno (zajisté, v produkčním kódu bychom se obtěžovali hlídat hodnoty nil, takže by se nám v poli pro plné jméno neobjevovaly texty "(null)"; také bychom měli ověřit, zda v žádném ze jmen nejsou mezery – v těchto jednoduchých příkladech se na to ale můžeme pokojně vyabstrahovat:), můžeme vložit plné jméno a korektně se z něj vygenerují jednotlivé části; jakkoli vložíme křestní jméno, jeho první písmeno se zvětší.
Jenže ouha: editor, v němž jsme to křestní jméno vložili, o tom "neví"! Zadáme-li křestní jméno s malým písmenem v textovém poli "First name", zůstane v něm malé písmeno (ačkoli, jak dokládá "Full name", ve skutečnosti je jméno v datovém modelu uloženo správně). Podobně, vložíme-li jméno s malým prvním písmenem prostřednictvím pole "Full name", zůstane špatná hodnota tam (tentokrát fakt, že do modelu se jméno uložilo správně opraveno, indikuje samozřejmě pro změnu pole "First name", jež svou hodnotu přebralo z modelu prostřednictvím kontroléru na základě notifikace KVO po změně):
To je proto, že jsme accessor setFirstname: implementovali špatně! Není totiž úkolem accessoru kontrolovat a upravovat – neřkuli snad dokonce odmítnout! – vloženou hodnotu; od toho jsou nezávislé samostatné validační metody.
Validace atributů
Jedna ze služeb systému KVC "pro starší a pokročilé", o níž jsme se dosud nezmínili, spočívá v tom, že systém KVC definuje standardní rozhraní pro validace atributů: pro jakýkoli atribut "xyz" můžeme v modelu definovat metodu validateXyz:error:, jež hodnotu atributu ověří, podle potřeby změní, nebo – pokud je zadaná hodnota neopravitelná – ohlásí chybu.
Dříve jsme se o tom nezmiňovali hlavně proto, že v samotném systému KVC jsou validace poněkud k ničemu: nikdo a nic je automaticky nepoužívá, programově klidně můžeme nastavit nevalidní hodnoty, a "všem to bude docela jedno". Jiná věc ovšem je, pokud prostřednictvím systému vazeb spojíme model (resp. kontrolér, který se o něj stará) s některým ze standardních objektů grafického uživatelského rozhraní Cocoa – ty totiž všechny berou validace v úvahu.
Můžeme začít tím, že implementujeme jednoduchou validaci, jež pouze zvětší prvé písmeno jakéhokoli textu, vloženého do atributu "firstname" – a kromě toho samozřejmě také odstraníme chybnou změnu atributu uvnitř accessoru setFirstname:
-(BOOL)validateFirstname:(id*)value error:(NSError**)error { *value=[*value capitalizedString]; return YES; } -(void)setFirstname:(NSString*)name { [firstname autorelease]; firstname=[name copy]; }
Validace fungují tak, že editor (v našem případě textové pole, opět samozřejmě prostřednictvím kontroléru) automaticky před ukončením editace zavolá validační metodu a předá jí referencí v argumentu value hodnotu, již má v úmyslu uložit do modelu. Validační metoda pak má tři možné vzorce chování:
- může prozkoumat navrženou hodnotu a zjistit, že je správná. Pak již nemusí dělat nic dalšího a jen vrátí hodnotu YES. My se v našem jednoduchém příkladu touto variantou neobtěžujeme;
- může navrženou hodnotu nahradit jinou, správnou hodnotou – proto je hodnota předána referencí (id*) a nikoli přímo. I v tomto případě metoda vrátí YES; editor ovšem snadno zjistí, že po volání validace se obsah argumentu value liší, a do modelu uloží hodnotu novou. Tu také sám zobrazí;
- zjistí-li metoda, že hodnota není správná a nelze ji opravit, uloží do argumentu error (také předaného referencí – NSError**) popis chyby zabalený do instance standardní třídy NSError, a vrátí NO. To v našem případě nenastává (ale ukážeme si takový příklad příště).
Ještě musíme v Interface Builderu ověřit, zda jsou u všech tří vazeb nastaveny přepínače "Validate Immediately". My si o nich řekneme trochu více, až se budeme zabývat kontrolérem třídy NSTreeController; prozatím se spokojíme s tím, že má-li validace v našem případě fungovat, musí být tento přepínač zapnutý.
Pokud jste snad po přidání výše uvedené validační metody a ověření NIBu ukvapeně zbuildovali a spustili aplikaci, vidíte, že se chování trochu změnilo, ale dosud není zcela správné: textové pole "First name" již funguje přesně jak má (tedy vložíme-li do něj text s malým písmenem na začátku, ihned po opuštění textového pole se písmeno automaticky zvětší). Zato však vkládání prostřednictvím pole "Full name" nezvětšuje písmeno vůbec... to je ale přece samozřejmé, vždyť jsme si před chvilkou jasně řekli, že programově klidně můžeme nastavit nevalidní hodnoty, a "všem to bude docela jedno" – a my nastavujeme hodnotu atributu "firstname" programově z metody setFullName:. Chceme-li validovat i atribut "fullName", musíme doplnit validační metodu i pro něj – ta by mohla vypadat v nejjednodušším případě třeba takto:
-(BOOL)validateFullName:(id*)value error:(NSError**)error { NSArray *a=[*value componentsSeparatedByString:@" "]; NSString *s=[a objectAtIndex:0]; if (![self validateFirstname:&s error:error]) return NO; *value=[NSString stringWithFormat:@"%@ %@",s,[a lastObject]]; return YES; }
Funkce nové metody je snad zřejmá, prostě pro validaci prvé části jména použijeme již hotovou metodu validateFirstname:error: (nejde jen o to, abychom si ušetřili práci; ještě mnohem důležitější je konsistence – pokud v budoucnosti validaci křestního jména nějak změníme, aplikuje se díky této implementaci změna i na validaci celého jména, což je samozřejmě správně).
Pokud nyní aplikaci zbuildujeme a spustíme, bude vše fungovat jak má: ať již vložíme křestní jméno prostřednictvím kteréhokoli pole, jeho prvé písmeno se automaticky zvětší – nejpozději ve chvíli, kdy textové pole opouštíme.
Obsah seriálu (více o seriálu):
- Nastal čas na kakao...
- Tak nejdřív kakao ochutnáme...
- Programovací jazyk C: velmi, velmi stručně
- Objective C: to si vysvětlíme podrobněji
- Co jsme si o Objective C ještě neřekli...
- Nastal čas na kakao - Vznik a zánik objektů
- Nastal čas na kakao - Kopírování objektů
- Nastal čas na kakao - Skryté podtřídy
- Nastal čas na kakao - Základní služby objektů
- Nastal čas na kakao - Jak správně psát v Objective C
- Nastal čas na kakao - Jak správně importovat
- Nastal čas na kakao - Podtřídy, delegáti, vkládání, jak se to rýmuje?
- Nastal čas na kakao - Využití kategorií namísto dědičnosti
- Nastal čas na kakao - Vkládání objektů a přesměrování zpráv
- Nastal čas na kakao - Inicializace a rušení objektů
- Nastal čas na kakao - Metody initWith... a designovaný inicializátor
- Nastal čas na kakao - Inicializace: tipy a triky
- Nastal čas na kakao - Accesory: přístup k proměnným instancí
- Nastal čas na kakao - Šedá je teorie, zelený je strom života...
- Nastal čas na kakao - Více o XCode: inspektory
- Nastal čas na kakao - Aplikace RSS2: datový model
- Nastal čas na kakao - Aplikace RSS: implementace datového modelu
- Nastal čas na kakao - Aplikace RSS: parsování XML
- Nastal čas na kakao - Interface Builder a uživatelské rozhraní
- Nastal čas na kakao - Interface Builder: atributy objektů
- Nastal čas na kakao - Interface Builder: atributy objektů
- Nastal čas na kakao - Druhý kontrolér a dokončení aplikace
- Nastal čas na kakao - Drobná vylepšení a zdokonalení...
- Nastal čas na kakao - Ladění
- Nastal čas na kakao - Třídy Foundation Kitu
- Nastal čas na kakao - Třídy Foundation Kitu (2)
- Nastal čas na kakao - Textové řetězce: NS(Mutable)String
- Nastal čas na kakao - Čísla, binární data a další...
- Nastal čas na kakao - Archivace objektů
- Nastal čas na kakao - Trocha magie, aneb distribuované objekty
- Nastal čas na kakao - Málem bychom zapomněli: NSAutoreleasePool
- Nastal čas na kakao - Zpracování výjimek: NSException
- Nastal čas na kakao - NSInvocation a černá magie
- Nastal čas na kakao - Kakao v Tygrovi
- Nastal čas na kakao - Notifikace: nepřímé předávání zpráv
- Nastal čas na kakao - NSUserDefaults
- Nastal čas na kakao - Co nového ve Foundation Kitu
- Nastal čas na kakao – s Intelem, s Intelem, jedeme do...
- Co nového v Xcode
- Začínáme s AppKitem
- Jak MVC v Kakau vypadá doopravdy?
- Jak MVC v Kakau vypadá doopravdy: dokončení
- Přehled tříd AppKitu
- Nastal čas na kakao - Přehled tříd AppKitu 2
- Přehled tříd AppKitu 3: zbývající třídy GUI
- Přehled tříd AppKitu 4: textový systém
- Nastal čas na kakao - Přehled tříd AppKitu 5: hlavně grafika
- Přehled tříd AppKitu 6: dokumentový systém
- Přehled tříd AppKitu 7: dokončení
- Pojmenované vlastnosti objektů
- Pojmenované vlastnosti objektů: implementace
- Pojmenované vlastnosti objektů: relace 1:N
- Pojmenované vlastnosti objektů: řazení jmen a agregační funkce
- Sledování změn objektů
- Sledování změn objektů – ukázka
- Sledování změn objektů – zdrojový kód
- Sledování změn objektů: kód modelu
- Sledování změn objektů: přímý přístup
- Kontroléry a vazby
- Vázání vazeb
- Další vazby s jednoduchým kontrolérem
- Implementace a použití převodu hodnot
- Validace hodnot
- Validace a chyby, a jedna hezká vazba...
- Práce s polem objektů
- Základní vazby NSArrayControlleru
- Převodníky, přepínače, placeholdery
- Mírná vylepšení v mezích zákona
- Objective C 2.0 - novinky z Leoparda
- NSTreeController
- Programování v Cocoa - Pár tipů a triků
- Programování v Cocoa - Základy kreslení
- Kterak nakreslit modrý obdélník...
- Další služby pro kreslení
- Obrázky a písmenka...
- Události a myš
- Lepší práce s myší
- Události klávesnice
- Input Management
- Příkazy a schránka
- Další události
- Táhni a padni
- Byli jsme na tahu; nyní padneme.
- Zvolme si, jak vhodit
- Drobnosti a chybičky
- Speciální případy tahání či házení
- Kterak táhnout něco, co neexistuje?
- Jak na sítě...
- NSURLConnection
- Safari za minutu
- Služby WebKitu
- Kakao v Leopardu
- Druhé Objective C
- Druhé Objective C: různé drobnosti
- Druhé Objective C: kategorie a protokoly
- Druhé Objective C: nový příkaz cyklu
- Druhé Objective C: atributy a accesory
- Druhé Objective C: atributy a accesory
- 64 je dvakrát 32
- Ubicumque dulce est, ibi et acidum invenies...
- Irbis: že prý žádné novinky?
- Blok sem, blok tam, nám už je to všechno jasné...
- Bloky jsou i v AppKitu
- Irbis a Foundation Kit
- Kde jsou má data?
- Kde jsou má data? V NSCache!
- Soubor, jméno, URL, jak se to rýmuje...
- Další podpora NSURL
- Zabíjení!
- A máme tady i...OS!
- Systémové prvky GUI
- Programování pro iOS 1. díl - Rozdíly mezi "i" a "Mac"
- Programování pro iOS - 2. Začínáme programovat
- Programování pro iOS - 3. základní ovladače a propojení GUI s kódem
- Programování pro iOS - 4. Varovná hlášení
- Programování pro iOS - 5. Rámce a jejich řídicí objekty
- Programování pro iOS - 6. Ukládání dat
- Programování pro iOS - 7. Správa paměti a starý restík
- Programování pro iOS - 8. Dokončení aplikace
- Programování pro iOS - 9. Jak dostat aplikaci do iPhone
- Programování pro iOS - 10. Instalace aplikace do cizího iPhone
- Programování pro iOS - 11. Jak dostat aplikaci do libovolného iPhone
- Programování pro iOS - 12. Touching!
- Programování pro iOS - 13. Kreslíme na iPhone
- Programování pro iOS - 14. Udělejme gesto
- Programování pro iOS - 15. Další gesta
- Programování pro iOS - 16. Více prstů, více zábavy
- Programování pro iOS - 17. Podpora standardních gest
- Programování pro iOS - 18. Recognizery v iOS
- Programování pro iOS - 19. Další standardní recognizery
- Programování pro iOS - 20. Co nového v iOSu
- Programování pro iOS - 21. "Multitasking"
- Programování pro iOS - 22. Nulla est honesta avaritia nisi temporis
- Programování pro iOS - 23. Jak se aktivovat, jsme-li v pozadí
- Programování pro iOS - 24. Zbývající drobnosti
- Programování pro iOS - 25. Řídicí objekty rámců
- Programování pro iOS - 26. Jak se dělá UIViewController
- Programování pro iOS - 27. Kde vzít rámce
- Programování pro iOS - 28. Základní služby
- Programování pro iOS - 29. Práce s rámci
- Programování pro iOS - 30. Rotace zařízení
- Programování pro iOS - 31. Správa paměti v rámcích
- Programování pro iOS - 32. Řídicí objekt pro tabulky
- Programování pro iOS - 33. Řídicí objekt pro strom
- Programování pro iOS - 33. Více o UINavigationControlleru
- Programování pro iOS - 35. Ještě jednou UINavigationController
- Programování pro iOS - 36. Po navigátoru taby
- Programování pro iOS - 37. Více o UITabBarControlleru
- Programování pro iOS - 38. Dokončení UITabBarControlleru
- Programování pro iOS - 39. UIPopoverController
- Programování pro iOS - 40. Další triky UIPopoverControlleru
- Programování pro iOS - 41. Zbývající služby UIPopoverControlleru
- Programování pro iOS - 42. UISplitViewController
- Programujeme v
iTunesXcode 4 - Programování pro iOS - 44. Předvolby Xcode 4
- Programování pro iOS - 45. Práce v Xcode 4
- Xcode 4: projekt a cíle
- Xcode 4: práce s cíli
- Xcode 4: Build Settings
- Xcode 4: Build Phases
- Xcode4: Build Phases podruhé
- Xcode 4: Co jsou to Build Rules?
- Xcode4: taje editoru
- Xcode4: automatické doplňování v editoru
- XIBy chyby
- Více o XIBech
- Editor XIBů
- Inspektory pro XIBy
- Vazby mezi objekty v XIBech
- Vazby mezi objekty v kódu
- Paletky Xcode pro XIBy
- Xcode 4: levý sloupec
- Xcode 4: okno Organizer
- Xcode 4: okno Organizer, část druhá
- Xcode 4: co je to Workspace?
- Xcode 4: základy schémat
- Xcode 4: akční schémata