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:
Začínáme s
Programování pro iOS - 7. Správa paměti a starý restík
15. září 2010, 00.00 | Základní funkcionalitu naší bouřkové aplikace máme hotovou. Ještě však pořád zbývá doplnit několik věcí. Minule jsme se naučili ukládat a načítat data. Dnes si ukážeme další standardní paměťovou techniku iOSu. A doplníme také jeden malý restík.
Operační systém iOS sice podporuje virtualizaci adres, takže každá aplikace běží ve svém vlastním adresovém prostoru, nemá ale virtualizaci paměti. Všechny aplikace se tedy musí vejít do reálné paměti, swapování momentálně nepoužívaných stránek na disk není k dispozici.
Proto je třeba pamětí šetřit, a na požádání dokonce uvolnit i tu, již aplikace sice používá, ale jejíž obsah může poměrně snadno znovu vygenerovat (připomeňme protokol NSDiscardableContent a třídu NSCache, které jsou ovšem v iOSu k dispozici až od verze 4 nahoru). Ačkoli u naší aplikace nejde o významné množství paměti, uvolňování implementujeme z cvičných důvodů.
Obvykle aplikace v iOS uvolňují paměť na základě standardní zprávy applicationDidReceiveMemoryWarning: v delegátu aplikace, případně didReceiveMemoryWarning na úrovni řídicích objektů rámců (odpovídající metody ostatně nalezneme i v projektu – aplikace Xcode je tam uložila při jeho vytváření na základě projektového vzoru). V našem případě se to ale zrovna nehodí, protože správu "paměti" máme zabalenou do samostatného zástupného objektu. Jistě, mohli bychom u něj doplnit službu purgeMemory a tu volat z řídicího objektu; tím bychom ale přišli o konsistenci rozhraní se standardní třídou NSMutableArray. Využijeme proto alternativní možnosti, standardních notifikací (co to je?).
Je to velmi jednoduché: dvě metody ve třídě OCSAutosavedMutableArray velmi mírně modifikujeme a třetí přidáme, to je vše:
// OCSAutosavedMutableArray.m
...
+(NSMutableArray*)array {
NSMutableArray *new=
(NSMutableArray*)[[self alloc] autorelease];
[[NSNotificationCenter defaultCenter]
addObserver:new
selector:@selector(memoryWarning)
name:UIApplicationDidReceiveMemoryWarningNotification
object:nil];
return new;
}
-(void)memoryWarning {
[contents release]; contents=nil;
}
-(void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[contents release];
[super dealloc];
}
...
Jde sem nebo se vzdaluje?
Už dávno jsme si slíbili, že paměti měření využijeme pro ohlášení toho, zda se bouřka blíží nebo vzdaluje, ale dosud jsme se k tomu nějak nedostali; doplníme proto jen v rychlosti a jednoduše tuto službu nyní.Nejprve přidáme "outlet" pro další textové pole:
// MainViewController.h
...
@interface MainViewController:UIViewController
<FlipsideViewControllerDelegate> {
IBOutlet UILabel *range,*speed;
}
...
a pak uložíme odpovídající objekt do hlavního rámce v Interface Builderu a s "outletem" jej propojíme pomocí "drátu"; to už umíme dávno.
Pak implementujeme patřičný kód do metody rangeButtonTapped:
// MainViewController.m
...
-(IBAction)rangeButtonTapped {
...
range.text=[NSString stringWithFormat:@"%.1 f km",dist/1000.];
if (self.history.count>0) {
NSDictionary *d=[self.history lastObject];
NSTimeInterval prev=[[d objectForKey:@"timestamp"]
timeIntervalSinceReferenceDate];
if ([NSDate timeIntervalSinceReferenceDate]-prev>2/*30*60*/)
speed.text=@"";
else {
double pdist=[[d objectForKey:@"dist"] doubleValue];
speed.text=pdist>dist?
@"Bouře se blíží!":
@"Bouře se vzdaluje...";
}
}
}
[self.history addObject:[NSDictionary
dictionaryWithObjectsAndKeys:
...
}
...
Je asi zřejmé, proč omezujeme výpočet pouze na měření v rozsahu půl hodiny: nemělo by valný smysl srovnávat měření den nebo ještě více vzdálená, jež se celkem evidentně budou týkat každé jiné bouřky.
Mimochodem, je asi zřejmé, že zde by toho bylo hodně co vylepšovat: předně, měli bychom vyhodnotit paměť měření hned po spuštění aplikace, aby se aktuální informace o rychlosti bouře neztratila při jejím ukončení a novém spuštění. Naopak bychom po uplynutí nějakého času mohli informaci – která již zřejmě nebude aktuální – zrušit. Měli bychom rozhodně také spočítat a zobrazit konkrétní rychlost, jakou se vůči pozorovateli bouřka pohybuje. Je-li tato rychlost hodně malá, měli bychom informovat, že bouře zůstává na místě, ani se nevzdaluje, ani se neblíží.
Mohli bychom také měnit grafické pozadí rámce podle toho, zda se bouře blíží nebo vzdaluje a jak rychle. Mohli bychom vyhodnotit více měření než jen to poslední a počítat průměrnou rychlost a také to, zda se pohyb celkově zrychluje nebo zpomaluje. Mohli bychom z těchto údajů a z aktuální naposledy spočtené vzdálenosti vyhodnotit, za jak dlouho bude bouřka přímo nad námi, a uživatele o tom informovat... vynalézavosti se meze nekladou, a cokoli z toho (nebo všechno najednou) si můžete implementovat za domácí úkol, chcete-li – jediné, co není zcela triviální, je změna grafického pozadí rámce. Přijdete na to sami dříve, než si v příštím dílu ukážeme, jak to nejsnáze řešit?
Nač máme ten druhý rámec?
Hned na samém začátku jsme zvolili projektový vzor "Utility Application"; v něm je vedle hlavního rámce ještě jeden – "FlipsideView" –, připravený pro nastavení a další informace o aplikaci. Rámec sám a jeho přepínání tam a zpět funguje "automaticky"; k tomu nám odpovídající kód vygeneroval hned na samém začátku projektový vzor, takže zde máme práci uspořenou; informace a nastavení ale musíme doplnit sami.
Stran informací si ovšem do rámce může napsat kdokoli cokoli – prostě tam vložíme UILabel a rovnou do něj napíšeme "Moje subgeniální bouřkoměrná aplikace, Copyright © MujMac, bla bla bla..."
S nastavením to zdaleka není tak jednoduché. Ba naopak; bohužel, znovu zde narážíme na to, že iOS nepodporuje objektové vazby "bindings", a proto je právě implementace takovýchto nastavení poměrně úmorná a ne zcela triviální.
Poněkud lepší to je u komplikovanějších aplikací, jež nastavení nemají přímo v jednom z vlastních rámců, ale úplně mimo aplikaci, v samostatném bloku předvoleb uvnitř aplikace Settings; tomu se ale budeme věnovat až mnohem později.
Pojďme si do pomocného rámce uložit dvojici předvoleb:
• výběr mezi metrickým a imperiálním zobrazením jednotek; k tomu použijeme třeba přepínač UISegmentedControl, jakési "mnohotlačítko", jež má jednu variantu vybranou a ostatní neaktivní (známe je třeba z aplikace Calendar jako přepínač mezi režimy seznamu, denním kalendářem a měsíčním přehledem);
• pro nastavení kapacity historie měření použijeme UIPickerView – to jsou ta "točítka", jejichž prostřednictvím se vkládají kupříkladu časy a data. Pokud bychom použili obyčejné textové pole, bylo by to snazší; pro volbu "pickeru" ale máme dva dobré důvody: (a) jeho použití je daleko pohodlnější pro uživatele, ale hlavně (b) se naučíme s ním pracovat. Jak uvidíme, vůbec to není triviální!
Nastavení jednotek
Nemáme-li "bindings", musíme každý ovladač pro nějakou předvolbu implementovat zhruba týmž způsobem:
• na samém začátku, když se rámec inicializuje, načteme aktuální hodnotu předvolby programově pomocí služeb třídy NSUserDefaults (se kterou jsme se důvěrně seznámili již v Mac OS X, a v iOS funguje stejně) – a pozměníme ovladač tak, aby ji zobrazoval. Vždy tedy musíme mít "outlet", jehož prostřednictvím se k ovladači dostaneme;
• kdykoli se obsah ovladače změní, musíme na to v kódu zareagovat, a předvolby opět prostřednictvím třídy NSUserDefaults změnit. Zde záleží na tom, jak který konkrétní ovladač přesně funguje; některé po změně posílají "akci" (pro nás právě takovým příkladem bude UISegmentedControl), jiné informují o změnách prostřednictvím služeb delegáta (to, jak uvidíme za chvilku, je právě UIPickerView).
Pro práci s "mnohotlačítkem" tedy potřebujeme jeden "outlet" a jednu "akci"; oba přidáme do hlavičkového souboru, který definuje rozhraní řídicího objektu sekundárního rámce:
// FlipsideViewController.h
...
@interface FlipsideViewController:UIViewController {
IBOutlet UISegmentedControl *units;
}
-(IBAction)unitsChanged;
...
Otevřeme objektovou síť tohoto rámce – tedy soubor "FlipsideView.xib" – v Interface Builderu. Do jejího rámce ("View") uložíme pomocí myši "Segmented Control" z "Library / Inputs & Values", upravíme vhodně texty v jeho tlačítkách a případně další atributy, a propojíme jej s kódem – to už by nyní pro nás dávno měla být stará vesta. Vypadat by to mohlo kupříkladu nějak takto:
přičemž návodný text "Používat jednotky" je samozřejmě praobyčejný UILabel, který jsme do rámce přidali, aby se v grafickém uživatelském rozhraní uživatel snáze orientoval.
Zbývá napsat odpovídající kód. Jak již víme, v řídicím objektu FlipsideViewController to budou dva prvky: nastavení po inicializaci rámce a uložení do předvoleb po změně. Kdo snad neznáte API třídy NSUserDefaults, nejprve se na ně podívejte – a pak už bude kód zcela zřejmý, včetně toho, že předvolbu ukládáme jako "ImperialUnits" s možností booleovského nastavení ano/ne:
// FlipsideViewController.m
...
-(void)viewDidLoad {
[super viewDidLoad];
units.selectedSegmentIndex=
[[NSUserDefaults standardUserDefaults]
boolForKey:@"ImperialUnits"]?1:0;
}
...
-(IBAction)unitsChanged {
[[NSUserDefaults standardUserDefaults]
setBool:units.selectedSegmentIndex==1
forKey:@"ImperialUnits"];
}
...
To ale není vše: tím jsme sice korektně implementovali možnost nastavení předvolby; ale ještě se podle ní také musíme řídit. Jinými slovy, kdekoli, kde zobrazujeme vzdálenost (případně rychlost, pokud jste si již doplnili výše navržené zobrazení toho, jak rychle se bouře blíží nebo vzdaluje), musíme vzít v potaz nastavení předvolby "ImperialUnits", a informaci zobrazit odpovídajícím způsobem.
Vzhledem k tomu, že se tak děje na více místech a dokonce ve dvou různých zdrojových souborech – vzdálenost zobrazuje jak hlavní rámec, tak i historie měření –, vyplatí se to sjednotit. V plnohodnotné produkční aplikaci bychom si asi pro takovéto pomocné služby vytvořili nový zdrojový soubor; zde si tu práci ušetříme, a službu poněkud nečistě přilepíme k řídicímu objektu hlavního rámce:
// MainViewController.h
...
@interface MainViewController:UIViewController {
...
@end
NSString *OCSLengthWithUnits(double metres);
...
Mimochodem: proč funkce a ne metoda? Neexistuje žádné jednoznačné kritérium, jež by v takovýchto případech preferovalo to či ono; metoda by ale byla ještě pevněji navázaná ke třídě MainViewController, s níž má nová funkčnost jen málo co dělat. Proto je zde asi funkce malinko lepší a čistší – stejně jako by byla nová třída, speciální jen pro tento účel; tu se nám ale pro takovou drobnost nevyplatí dělat.
Uvnitř implementace řídicího objektu si ukážeme zároveň obojí: jak obsah funkce, tak i její použití:
// MainViewController.m
...
NSString *OCSLengthWithUnits(double metres) {
if ([[NSUserDefaults standardUserDefaults]
boolForKey:@"ImperialUnits"])
return [NSString
stringWithFormat:@"%.1f mi",metres/1609.344];
return [NSString
stringWithFormat:@"%.1f km",metres/1000.];
}
@implementation MainViewController
...
-(IBAction)rangeButtonTapped {
...
range.text=OCSLengthWithUnits(dist);
...
}
...
Podobně triviální bude použití i na druhém místě:
// HistoryViewController.m
...
-(UITableViewCell*)tableView:(UITableView*)tableView
cellForRowAtIndexPath:(NSIndexPath*)indexPath {
...
NSDictionary *d=[delegate.history
objectAtIndex:indexPath.row];
cell.textLabel.text=
OCSLengthWithUnits([[d objectForKey:@"dist"] doubleValue]);
...
}
...
Kapacita historie a práce s UIPickerem
S kapacitou historie to bude horší; jak hned uvidíme, s ovládáním třídy UIPicker je spousta práce. Nejprve si do rozhraní přidáme odpovídající "outlet"; navíc připojíme odkaz na oba protokoly, jež nadále musí řídicí objekt sekundárního rámce implementovat – datový zdroj a delegát "pickeru":// FlipsideViewController.h
...
@interface FlipsideViewController:UIViewController
<UIPickerViewDelegate, UIPickerViewDataSource> {
IBOutlet UISegmentedControl *units;
IBOutlet UIPickerView *capacity;
}
...
Novou "akci" ovšem nepotřebujeme, jelikož UIPickerView informuje o změnách prostřednictvím metod delegáta.
Pak v Interface Builderu "picker" do rámce uložíme – nalezneme jej pro změnu ve skupině "Data Views" okna "Library" – a propojíme s kódem. Tentokrát musíme natáhnout trojici "drátů": outlet, datový zdroj a delegáta:
Programování nás čeká poněkud více než minule; především se totiž vůbec musíme postarat o to, aby "picker" měl dva sloupce, a v každém z nich aby se zobrazovaly číslice od 0 do 9 – to je pro zadávání kapacity historie, u níž nemají valný smysl hodnoty přesahující 100, asi ideální.
K tomu je třeba implementovat následující metody – odpovídající zprávy "picker" posílá při konfiguraci datovému zdroji a delegátovi, a na jejich základě se zobrazí jeho obsah:
// FlipsideViewController.m
...
-(NSInteger)numberOfComponentsInPickerView:
(UIPickerView*)pickerView {
return 2;
}
-(NSInteger)pickerView:(UIPickerView*)pickerView
numberOfRowsInComponent:(NSInteger)component {
return 10;
}
-(NSString*)pickerView:(UIPickerView*)pickerView
titleForRow:(NSInteger)row
forComponent:(NSInteger)component {
return [NSString stringWithFormat:@"%d",row];
}
...
Teprve nyní na základě této konfigurace můžeme implementovat vlastní práci s předvolbou – nazveme ji HistoryCapacity a bude v ní číslo, určující kapacitu pole s uloženými měřeními:
// FlipsideViewController.m
...
-(void)viewDidLoad {
[super viewDidLoad];
units.selectedSegmentIndex=
[[NSUserDefaults standardUserDefaults]
boolForKey:@"ImperialUnits"]?1:0;
int hc=[[NSUserDefaults standardUserDefaults]
integerForKey:@"HistoryCapacity"];
[capacity selectRow:hc/10 inComponent:0 animated:NO];
[capacity selectRow:hc%10 inComponent:1 animated:NO];
}
...
-(void)pickerView:(UIPickerView*)pv
didSelectRow:(NSInteger)row
inComponent:(NSInteger)component {
[[NSUserDefaults standardUserDefaults]
setInteger:[pv selectedRowInComponent:0]*10+
[pv selectedRowInComponent:1]
forKey:@"HistoryCapacity"];
}
...
Zbývá opět použití předvolby v kódu hlavního rámce, kde omezujeme počet položek v paměti – to je samozřejmě triviální:
// MainViewController.m
...
-(IBAction)rangeButtonTapped {
...
int hc=[[NSUserDefaults standardUserDefaults]
integerForKey:@"HistoryCapacity"];
while (self.history.count>hc)
[self.history removeObjectAtIndex:0];
}
}
...
Ale pozor, není to vše! Uvědomme si, že po instalaci a prvém spuštění aplikace musí být počet položek v historii nenulový; někde tedy musíme určit výchozí hodnotu, která platí pokud ještě nikdy nikdo do předvoleb nezasáhl. K tomu slouží standardně tzv. registrační doména třídy NSUserDefaults; nejvhodnější metodou pro její nastavení je inicializace nějakého hodně "základního" objektu, nejspíše asi aplikačního delegáta:
// iOS_3_ExampleAppDelegate.m
...
+(void)initialize {
[[NSUserDefaults standardUserDefaults]
registerDefaults:
[NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:50],@"HistoryCapacity",
nil]];
}
@end
Tím máme aplikaci skoro hotovou; příště už ji dokončí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