Minule jsme se zaΦali na konkrΘtnφch p°φkladech seznamovat s pou₧itφm nejb∞₧n∞jÜφch t°φd Foundation Kitu. Dnes si ukß₧eme n∞kolik dalÜφch p°φklad∙.
NS(Mutable)Dictionary
HaÜovacφ tabulky, je₧ Foundation Kit nabφzφ prost°ednictvφm t°φd NSDictionary a NSMutableDictionary, pat°φ mezi neju₧φvan∞jÜφ slu₧by v∙bec: jsou toti₧ nesmφrn∞ pohodlnΘ a flexibilnφ. P°ipome≥me si minul² p°φklad, ve kterΘm jsme vyu₧ili NSCountedSet pro frekvenΦnφ anal²zu danΘho textu. Dnes si ukß₧eme analogick² p°φklad, v n∞m₧ nßm poslou₧φ t°φda NSMutableDictionary pro vytvo°enφ rejst°φku. Podobn∞ jako minule si zßrove≥ ukß₧eme funkci a slu₧by n∞kolika dalÜφch t°φd û p°φkladem bude kompletnφ program.
NßÜ progrßmek vytvo°φ kompletnφ index vÜech soubor∙ HTML v zadanΘ slo₧ce a ve vÜech slo₧kßch vno°en²ch û pro ka₧dΘ slovo ud∞lß seznam vÜech dokument∙, ve kter²ch je toto slovo vyu₧ito. Program bude o n∞co luxusn∞jÜφ ne₧ minul² p°φklad; obsahuje t°eba dek≤dovßnφ argument∙ p°φkazovΘho °ßdku. Nejprve se podφvßme na zdrojov² text (kompletnφ program zabere mΘn∞ ne₧ 60 °ßdk∙), a pak si n∞kterΘ p°φkazy vysv∞tlφme podrobn∞ji:
if (![output writeToFile:ofile atomically:NO]) NSLog(@"!!! Can't write %@",ofile);
NSLog(@"Index successfully written to \"%@\"",ofile);
[pool release];
exit(0);
return 0;
}
Na °ßdku s komentß°em *1* zaΦφnß zpracovßnφ vstupnφch argument∙. Bylo by zbyteΦnΘ na tomto mφst∞ podrobn∞ popisovat slu₧by t°φdy NSUserDefaults. Za struΦnou zmφnku vÜak stojφ to, ₧e krom∞ dek≤dovßnφ p°φkazovΘho °ßdku zajiÜ¥uje p°φstup k velmi obecnΘ databßzi u₧ivatelsk²ch p°edvoleb. Bez dalÜφho programovßnφ mßme tedy k dispozici nejen p°φkazov² °ßdek, ale m∙₧eme i fixovat standardnφ hodnoty argument∙ v tΘto databßzi a nßÜ program je automaticky vyu₧ije.
Hlavnφ d∙vod, proΦ se zde t°φdou NSUserDefaults v∙bec zab²vßme, vÜak je ilustrace jednΘ z velmi p°φjemn²ch vlastnostφ API Cocoa, kterou je d∙slednΘ vyu₧φvßnφ polymorfismu. VÜimn∞te si, ₧e pro zφskßnφ hodnoty po₧adovanΘho argumentu z objektu NSUserDefaults slou₧φ p°esn∞ stejnß zprßva (objectForKey:), jako pro zφskßnφ hodnoty po₧adovanΘho klφΦe z objektu NSDictionary (na °ßdku s komentß°em *5* nebo na °ßdku za komentß°em *6*). To p°inßÜφ dv∞ obrovskΘ v²hody:
* doba pot°ebnß k nauΦenφ se API Cocoa je mnohem kratÜφ ne₧ doba pot°ebnß pro nauΦenφ se jin²ch û i daleko chudÜφch û API;
* Φasto se hodφ i p°φmΘ vyu₧itφ polymorfismu pro v∞tÜφ flexibilitu k≤du.
Obsah °ßdku *2* je vÜe, co pot°ebujeme pro vyhledßnφ vÜech soubor∙, je₧ budeme indexovat. Obsah p°φkazu for zajistφ prochßzenφ vÜech soubor∙ uvnit° slo₧ky ifolder a slo₧ek vno°en²ch, a nßsledujφcφ p°φkaz if z nich vybere jen soubory HTML.
Makra NS_DURING (*3*), NS_HANDLER a NS_ENDHANDLER jsou v Cocoa standardnφ obsluhou v²jimek. FunkΦn∞ tedy odpovφdajφ kombinaci try/catch z C++, jsou vÜak mnohem efektivn∞jÜφ. V naÜem jednoduchΘm progrßmku slou₧φ k tomu, aby û pokud p°i zpracovßnφ n∞kterΘho souboru dojde k v²jimce û nebyl program ukonΦen, ale aby indexovßnφ pokraΦovalo dalÜφm souborem.
Na °ßdku *4* pou₧φvßme t°φdu NSAttributedString, kterß dokß₧e korektn∞ naΦφst HTML soubor a vrßtit jeho textov² obsah jako standardnφ string (toho vyu₧ijeme hned na nßsledujφcφm °ßdku). Pro vyhledßnφ jednotliv²ch slov v jeho obsahu pou₧ijeme NSScanner p°esn∞ stejn∞ jako v minulΘm p°φkladu.
T°i °ßdky od komentß°e *5* obsahujφ vlastnφ indexovßnφ. Jeho logika je jednoduchß: nejprve z objektu NSMutableDictionary (kter² je ulo₧en v prom∞nnΘ index) zφskßme objekt, jeho₧ klφΦem je danΘ slovo. Pokud takov² objekt dosud neexistuje (proto₧e jde o prvnφ v²skyt danΘho slova), vytvo°φme jej (jako prßzdn² NSMutableSet) a ihned jej û s dan²m slovem jako klφΦem û vlo₧φme do indexu (to je obsahem druhΘho °ßdku). T°etφ °ßdek je trivißlnφ, prost∞ do objektu NSMutableSet vlo₧φ jmΘno souboru, ve kterΘm jsme danΘ slovo nalezli.
Je snad z°ejmΘ, ₧e tφmto zp∙sobem nakonec v prom∞nnΘ index vybudujeme skuteΦn² index, v n∞m₧ klφΦi budou jednotlivß slova a odpovφdajφcφmi hodnotami mno₧iny obsahujφcφ jmΘna vÜech dokument∙, ve kter²ch se danΘ slovo vyskytuje. Mimochodem, mal² kvφz pro pozornΘ Φtenß°e: proΦ jsme pro seznamy soubor∙ pou₧ili t°φdu NSMutableSet a ne t°φdu NSMutableArray?
Mohli bychom sice index vypsat p°φmo (p°φkazem [index writeToFile:ofile...]), jen₧e pak by slova nebyla set°φd∞nß podle abecedy. Proto vytvo°φme NSMutableString, do kterΘho na pouh²ch dvou °ßdcφch (*6* a nßsledujφcφ) vygenerujeme v²stupnφ seznam slov a odpovφdajφcφch soubor∙ v abecednφm po°adφ. Srovnejme p°φkaz pro t°φd∞nφ (sortedArrayUsingSelector:) s obdobn²m p°φkazem z minulΘho p°φkladu ûtentokrßt vyu₧φvßme dynamickΘho systΘmu Objective C a prost∞ uvedeme zprßvu, jejφ₧ pomocφ se majφ p°i t°φd∞nφ slova porovnßvat (je jφ standardnφ zprßva compare:, kterou v lze API Cocoa srovnat libovolnΘ dva objekty, nad nimi₧ je definovßna relace menÜφ/v∞tÜφ).
Jak je vid∞t na v²pisu v HTML podob∞ Φlßnku na Chip CD, pro kompletnφ indexovßnφ cca t°φ megabajt∙ HTML textu staΦily necelΘ dv∞ minuty. V²sledek (samoz°ejm∞ jen z malΘ Φßsti) pak vidφme na obrßzku.
NS(Mutable)String
╪adu p°φklad∙ prßce s objekty t∞chto t°φd jsme ji₧ vid∞li. V minulΘm p°φkladu jsme pomocφ t°φdy NSMutableString generovali v²stupnφ data, NSString byl pou₧it pro naΦφtßnφ vstupnφch soubor∙ i pro ·daje z argument∙ p°φkazovΘho °ßdku... V tomto odstavci si ukß₧eme pßr dalÜφch slu₧eb podrobn∞ji.
// mo₧nostφ vytvo°it °et∞zec je °ada:
id a=@"Toto je statick² objekt t°φdy NSString";
char *xx="M∙₧eme samoz°ejm∞ vyu₧φt i prom∞nnΘ \"char *\"";
id b=[NSMutableString stringWithCString:xx];
char *yy="I\0kdy₧\0obsahujφ\0nulovΘ\0znaky\0!"
id c=[NSString stringWithCString:yy length:30];
// °et∞zec lze naΦφst p°φmo ze souboru:
id d=[NSString stringWithContentsOfFile:@"/tmp/something.text"];
// nebo vytvo°it pomocφ "printf"-formßtu:
id e=[NSString stringWithFormat:@"total:%d, %s, %@, %5.3f\n",1,"ahoj",a,3.14159];
// m∙₧eme si takΘ vy₧ßdat automatick² "p°eklad" prost°ednictvφm
// p°ekladovΘ tabulky v aktivnφm adresß°i lproj (podrobnosti viz NSBundle):
id f=[NSString localizedStringWithFormat:@"%d files",ff];
// v²Üe uveden² p°φklad vytvo°φ nap°. p°i aktivnφ ΦeÜtin∞ a
// odpovφdajφcφ polo₧ce v tabulce string∙ °et∞zec
// @"15 soubor∙".
╪et∞zce Φasto generujφ i jinΘ t°φdy (nap°. libovoln² objekt OpenStepu vrßtφ NSString, obsahujφcφ jeho popis, na zßklad∞ zprßvy description). Jin²m hezk²m p°φkladem je NSArray û objekty tΘto t°φdy um∞jφ vytvo°it °et∞zec dan² kombinacφ vÜech obsa₧en²ch prvk∙ a libovolnΘho odd∞lovaΦe:
Zßkladnφ slu₧by pro prßci s °et∞zci samoz°ejm∞ zahrnujφ nejr∙zn∞jÜφ kombinace a rozklady. Uka₧me si n∞kolik p°φklad∙, vyu₧φvajφcφch °et∞zce a û f vytvo°enΘ v prvnφm p°φkladu:
NSLog(@"%@",[f stringByAppendingString:f]);
// vypφÜe "15 soubor∙15 soubor∙"
NSLog(@"%@",[f stringByAppendingFormat:@" je prost∞ %@",f]);
// vypφÜe "15 soubor∙ je prost∞ 15 soubor∙"
NSArray a=[e componentsSeparatedByString:@", "];
// vytvo°φ pole @"total:1",@"ahoj",@"Toto ... NSString",@"3.142"
NSLog(@"%@",[c substringFromIndex:29]);
// vypφÜe "!"
[b deleteCharactersInRange:(NSRange){8,8}];
// b obsahuje "M∙₧eme prom∞nnΘ "char *""
[b appendString:@" pou₧φt"];
// b obsahuje "M∙₧eme prom∞nnΘ "char *" pou₧φt"
[b insertString:@"snadno " atIndex:7];
// b obsahuje "M∙₧eme snadno prom∞nnΘ "char *" pou₧φt"
Pro oznaΦovßnφ Φßstφ °et∞zc∙ a pro vyhledßvßnφ slou₧φ typ NSRange û obyΦejnß struktura, obsahujφcφ dv∞ Φφsla, pozici a dΘlku:
NSLog(@"\"je\" je na pozici %d, p°ed nφm je \"%@\"",r.location,[a substringToIndex:r.location]);
// vypφÜe ""je" je na pozici 5, p°ed nφm je "Toto ""
Prost°ednictvφm p°epφnaΦ∙ si m∙₧eme vy₧ßdat i hledßnφ odzadu, hledßnφ bez ohledu na velikost pφsmen nebo hledßnφ pouze od zadanΘ pozice. Omezit lze takΘ rozsah prohledßvanΘho °et∞zce. Pro zßkladnφ a nejΦast∞ji pot°ebnß porovnßvßnφ jsou samoz°ejm∞ k dispozici hotovΘ metody:
if ([a hasPrefix:@"Toto"]) // platφ
if ([c hasSuffix:@"!"]) // platφ
if ([d isEqual:e]) // neplatφ
Zajφmavß je i mo₧nost vy₧ßdat si nejdelÜφ spoleΦn² prefix dvou °et∞zc∙. I zde mßme mo₧nost volit, zda se mß nebo nemß brßt v ·vahu velikost pφsmen:
Prozatφm jsme se v∙bec nezab²vali vnit°nφm k≤dovßnφm °et∞zce. To je v objektovΘm prost°edφ samoz°ejmΘ û do vnit°nφho k≤dovßnφ nßm p°ece nic nenφ a zajφmajφ nßs pouze zprßvy, kterΘ je objekt schopen zpracovat. K≤dovßnφ vÜak m∙₧e b²t zajφmavΘ ze dvou d∙vod∙ û p°edn∞ z pou₧itΘho k≤dovßnφ vypl²vß rozsah znak∙, kterΘ °et∞zec m∙₧e obsahovat; druh²m d∙vodem m∙₧e b²t programovß volba k≤dovßnφ pro konkrΘtnφ ·Φel û nap°φklad pro uklßdßnφ do souboru bude asi nejv²hodn∞jÜφ k≤dovßnφ, kterΘ zabere nejmΘn∞ mφsta.
Zßkladnφm k≤dovßnφm pro t°φdu NSString je Unicode v tom smyslu, ₧e °et∞zce reprezentovanΘ objekty t°φdy NSString mohou obsahovat libovolnΘ znaky Unicode, a ₧e metody pro p°φm² p°φstup do °et∞zce (nap°. metoda characterAtIndex:) operujφ prßv∞ s Üestnßctibitov²mi k≤dy znak∙ podle standardu Unicode. Pro dalÜφ k≤dovßnφ mßme k dispozici p°eddefinovan² typ NSStringEncoding, kter² reprezentuje k≤dovßnφ, a nßsledujφcφ metody:
// vypφÜeme vÜechna k≤dovßnφ, kterß jsou k dispozici
Tφm samoz°ejm∞ mo₧nosti NSString∙ zdaleka nekonΦφ; na ·rovni tohoto Φlßnku by vÜak nem∞lo smysl podrobn∞ popisovat vÜechny metody. Proto se ji₧ seznßmφme jen se samostatnou skupinou slu₧eb, kterΘ zajiÜ¥ujφ korektnφ prßci s nßzvy soubor∙ a adresß°∙ û samoz°ejm∞ v konkrΘtnφm hostitelskΘm operaΦnφm systΘmu, tak₧e programßtor se nemusφ starat o to, odd∞lujφ-li se jednotlivΘ polo₧ky lomφtkem, obrßcen²m lomφtkem nebo t°eba dvojteΦkou:
// pro u₧ivatele Steve vypφÜe "/Users/Steve/Apps/Test.app"
NSString *p=@"/oc/RootTemp";
NSLog(@"%@",[p stringByResolvingSymlinksInPath]);
// u m∞ vypφÜe "/private/tmp", proto₧e
// /oc/RootTemp je link ("zßstupce") slo₧ky /private/tmp
NSString *p=@"~/../oc/./RootTemp/./TmpFile";
NSLog(@"%@",[p stringByStandardizingPath]);
// vypφÜe "/Users/oc/RootTemp/TmpFile"
Shrnutφ
Vid∞li jsme p°φklady pou₧itφ dvou nesmφrn∞ Φasto vyu₧φvan²ch t°φd û NS(Mutable)Dictionary a NS(Mutable)String. Bez podrobn∞jÜφho v²kladu jsme se seznßmili s °adou dalÜφch t°φd API Cocoa, mj. s NSUserDefaults nebo NSFileManager, a ukßzali jsme si jin² p°φklad pou₧itφ t°φdy NSMutableSet. V p°φÜtφm dφlu se podφvßme na dalÜφ zajφmavΘ t°φdy Foundation Kitu.