<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Je to divočina &#187; Objective-C</title>
	<atom:link href="http://blog.urbasek.cz/tag/objective-c/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.urbasek.cz</link>
	<description>Práce na volné noze je divočina! Na tomto blogu publikuji zápisky ze svého safari. Ve zbývajícím čase programuji aplikace pro iPhone.</description>
	<lastBuildDate>Fri, 29 Nov 2013 15:44:55 +0000</lastBuildDate>
	<language>cs-CZ</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=3.9.40</generator>
	<item>
		<title>Cocoa Objective-C a práce s pamětí</title>
		<link>http://blog.urbasek.cz/cocoa-objective-c-a-prace-s-pameti/</link>
		<comments>http://blog.urbasek.cz/cocoa-objective-c-a-prace-s-pameti/#comments</comments>
		<pubDate>Thu, 01 Apr 2010 11:34:51 +0000</pubDate>
		<dc:creator><![CDATA[JIří Urbášek]]></dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[Programování]]></category>

		<guid isPermaLink="false">http://blog.urbasek.cz/?p=14</guid>
		<description><![CDATA[Práce s pamětí v objective-c je velmi zásadní (přece jen je to klasické Cčko v novém kabátě). Zvlášť, pokud programujeme pro iPhone, který nepoužívá garbage collector, musíme se o vše postarat sami. Určitě jste se někdy setkali s názvy jako alloc, init, release, dealloc, retain, či autorelease. Z Cčka víme, že pokud nějakou proměnnou vytvoříme...<br /><a class="more-link" href="http://blog.urbasek.cz/cocoa-objective-c-a-prace-s-pameti/">Continue reading &#187;</a>]]></description>
				<content:encoded><![CDATA[<p>Práce s pamětí v objective-c je velmi zásadní (přece jen je to klasické Cčko v novém kabátě). Zvlášť, pokud programujeme pro iPhone, který nepoužívá garbage collector, musíme se o vše postarat sami. Určitě jste se někdy setkali s názvy jako <code>alloc</code>, <code>init</code>, <code>release</code>, <code>dealloc</code>, <code>retain</code>, či <code>autorelease</code>. Z Cčka víme, že pokud nějakou proměnnou vytvoříme pomocí <code>malloc</code>, nesmíme ji zapomenout zase odalokovat pomocí <code>free</code>. Obdobně v C++ je to <code>new</code> a <code>delete</code>. V Objective-C je to podobné, abychom mohli správně uvolnit již nepotřebnou paměť, musíme vědět, kdo je <em>vlastníkem</em> daného objektu.</p>
<p>V tomto článku si povíme kdy a jak správně uvolňovat objekty, které používáme, představíme si objective-c property a vysvětlíme si různé typy, kterými property pracují s pamětí. Na závěr si povíme něco o automatickém uvolňování paměti (nikoliv o garbage collectoru).</p>
<p><code><span id="more-14"></span></code></p>
<h2>Retain Count &#8211; počítáme reference</h2>
<p>Práce s pamětí v objective-c a Cocoa frameworku je založena na počítání referencí (odkazů) na objekty. To znamená, že pokud si vytvoříme nějaký objekt &#8211; jsme jeho vlastníkem &#8211; zvýší se jeho počet referencí (<em>retain count </em>nebo také <em>reference count</em>) o číslo 1. Pokud tento objekt již nechceme používat, naznačíme to tím, že jeho <em>retain count</em> opět snížíme. Jakmile počet referencí objektu dosáhne hodnoty 0, objekt bude automaticky odalokován. Ale pozor! Ne vždy jsme vlastníkem objektu, přestože ho používáme.</p>
<h3>Vlastnictví objektů</h3>
<ul>
<li>Vlastníkem objektu jsme tehdy, pokud ho sami vytvoříme. Objekty se vytváří pomocí metod začínajících na <code>alloc</code>, <code>new</code> nebo metod obsahujících slovo <code>copy</code> (např. <code>alloc</code>, <code>newObject</code>, <code>mutableCopy</code>)</li>
<li>Vlastnictví objektu se dá získat také prostřednictvím metody <code>retain</code>, o které si povíme za chvíli</li>
<li>Pokud jsme vlastníky objektu, jsme zodpovědní za jeho uvolnění (<em>relinquishing ownership</em>) &#8211; typicky pomocí metod <code>release</code>, či <code>autorelease</code></li>
<li>Naproti tomu, pokud objekt nevlastníme, <strong>nesmíme</strong> ho uvolňovat</li>
</ul>
<p>Několik příkladů vytvoření objektů:</p>
<pre lang="objc">NSString *message = [[NSString alloc]
                      initWithString:@"Toto je muj retezec."];
NSString *copiedMessage = [message copy];
copiedMessage = @"Tento retezec je take muj!";

NSLog(message);
NSLog(copiedMessage);

[message release];
[copiedMessage release]</pre>
<p>Doplňme tedy, že při vytvoření objektu se automaticky nastaví retain count na hodnotu 1. Metoda <code>release</code> nedělá nic jiného, než že tuto hodnotu opět sníží (vlastně dělá ještě něco jiného &#8211; vrací <code>self</code>, tzn. objekt, jehož reference count byl snížen).</p>
<h3>Vypůjčené objekty</h3>
<p>Ptáte se nyní, jakéže jsou ty objekty, které používáme ale nevlastníme je?<br />
Jejich vytváření mají na starosti třídní metody (tzv. <em>Convenience Methods</em>). To jsou metody, které většinou na začátku svého jména specifikují datový typ, který vrací v návratové hodnotě. Tedy například u třídy <code>NSString</code> to může být <code>stringWithString:</code>, u třídy <code>NSDate</code> <code>date</code> u <code>NSArray</code> <code>arrayWithObjects:</code> a mnoho dalších. U těchto objektů nejsme vlastníky, třída je pro nás vytvoří a předá nám pouze referenci (odkaz na paměť), kde se tento objekt vyskytuje. Jelikož si ho třída vytvořila sama, tak se také sama postará o jeho správné uvolnění.</p>
<pre lang="objc">NSString *message = [NSString
                     stringWithString:@"Tento retezec nevlastnim ja."];
message = @"Ale ja chci svuj retezec...";

NSString *myOwnMessage = [message retain];
myOwnMessage = @"Jupi, ted mam svuj vlastni retezec";
message = @"A muzu si obsah sveho vlastniho retezce zmenit i v promenne message";

NSLog(message);
NSLog(myOwnMessage);

[myOwnMessage release];
// nikoliv [message release]</pre>
<p>Pro úplnost se ještě podíváme na následující ukázku kódu :</p>
<pre lang="objc">NSString *myString = [[NSString alloc] initWithString: @"tohle je muj retezec"];
NSString *mySecongString = [[NSString
                             stringWithString:@"tenhle je taky muj"] retain];

//naproti tomu
NSString *aString = [NSString stringWithString:@"tenhle retezec ale neni muj"];
NSString *aSecondString = [[[NSString alloc]
                            initWithString: @"a tenhle rovnez neni muj"] autorelease];

[myString release];
[mySecondString release];</pre>
<p>Z posledního ukázkového kódu by mělo být také zřejmé, jaký je význam použitých metod.</p>
<ul>
<li>Metoda <code>retain</code> zvyšuje čítač referencí u daného objektu (pro lepší použitelnost opět vrací <code>self</code>).</li>
<li>Metoda <code>autorelease</code> dělá velmi podobnou věc, jako metoda <code>release</code>, akorát s tím rozdílem, že čítač referencí sníží až někdy později, automaticky.</li>
</ul>
<p>Ddy se teda uvolní objekty, kterým jsme zaslali zprávu <code>autorelease</code>, to se dozvíme až, si budeme povídat o <code>NSAutoreleasePool</code>.</p>
<h2>Objective-C 2.0 Property to vyřeší za nás</h2>
<p>Možná znáte property z jiných programovacích jazyků, jako například z C#, či Javy. Možná netušíte, co to property jsou &#8211; jsou to prostě gettery a settery.</p>
<h3>Nastavení property nikdy nebylo jednodušší</h3>
<p>Objective-C 2.0 nám umožňuje definovat tyto metody, aniž bychom museli mít přímo jejich implementaci ve zdrojovém kódu. Můžeme si zvolit jakým způsobem tyto metody budou zacházet s pamětí privátních proměnných &#8211; jestli zvýší retain count nebo zkopírují celý objekt do nového, či jen přiřadí ukazatel na adresu. A jak na to?</p>
<h3>Retain, copy, assign, nonatomic nebo readonly &#8230;?</h3>
<p>Nejdůležitější <em>nastavení</em> je potřeba učinit při definici property v hlavičkovém souboru &#8211; klíčovým slovem <code>@property. S</code>yntaxe je následující:</p>
<pre lang="objc">@property [(attribute [, attribute2, ...])] type name;</pre>
<p>Pak už jen stačí v souboru s implementací říct kompilátoru slovíčkem <code>@synthesize,</code> ať se o vše postará sám.</p>
<p>Právě význam volitelných atributů je potřeba si pořádně vysvětlit &#8211; určitě jste se už setkali s definicí jako <code>@property (nonatomic, retain) ...</code> ale je nutno zdůraznit že toto není zdaleka jediný a ne vždy ten nejlepší způsob, jak bychom mohli své property definovat.</p>
<h4>Atributy a správa paměti</h4>
<p>Z hlediska správy paměti máme celkem 3 možnosti, jak se můžou vygenerované settery chovat:</p>
<ul>
<li><code>assign</code><br />
<em> obyčejné</em> přiřazení &#8211; tímto atributem říkáme, že do privátní proměnné se má přiřadit adresa objektu, kterým nastavujeme hodnotu (parametr setteru), ale retain count <strong>není</strong> zvýšen. Toto je defaultní typ, který se použije, když nespecifikujeme žádný atribut, a většinou  je toto chování pro nás nežádoucí, ale například property <code>dataSource</code> a <code>delegate</code> pro <code>UITableView</code> právě tento přístup k paměti používají.</li>
<li><code>retain</code><br />
říká, že setter přiřadí adresu objektu ke do privátní proměnné a zároveň zvýší její retain count pomocí metody <code>retain</code>. Díky tomu objekt může s proměnnou pracovat tak dlouho, dokud si ji sám neuvolní. Ale pozor, pracujeme pořád se stejnou adresou, takže pokud objekt, který jsme do proměnné přiřadili, někdy později změní svoji hodnotu, projeví se to i v instanční proměnné. Tento způsob používáme nejčastěji.</li>
<li><code>copy</code><br />
pokud potřebujeme zajistit, aby hodnotu privátní proměnné nebylo možné měnit <em>z vnějšku</em>, specifikujeme právě tento atribut. Který namísto metody <code>retain</code> zavolá na proměnnou metodu <code>copy</code>, čímž zkopíruje obsah přiřazovaného objektu na jiné paměťové místo a tím tak zajistí nezávislost na původním objektu.</li>
</ul>
<p><em>Vygenerované</em> settery mohou vypadat zhruba následovně:</p>
<pre lang="objc">// @property NSString *string;
-(void)setString:(NSString *)newString {
    if (string != newString) {
        string = newString;
    }
} 

// @property (retain) NSString *string;
-(void)setString:(NSString *)newString {
    if (string != newString) {
        [string release];
        string = [newString retain];
    }
} 

// @property (copy) NSString *string;
-(void)setString:(NSString *)newString {
    if (string != newString) {
        [string release];
        string = [newString copy];
    }
}</pre>
<p>Pokud od getterů, či setterů vyžadujeme, musíme si je už definovat sami.</p>
<p>Property umožňují definovat více atributů, než jen výše uvedené. Například <code>nonatomic</code>, či <code>readonly</code>. Ale jelikož tyto se přimo netýkají správy paměti, nebudu se o nich zde zmiňovat.</p>
<h2>Automatické uvolnění paměti</h2>
<p>Položili jste si někdy otázku jaký je rozdíl mezi <code>release</code> a <code>autorelease</code>? Cože tam má jedna metoda automatického a druhá ne? Odpovědí je <code>NSAutoreleasePool</code>.</p>
<h3>Hromádka odložených objektů</h3>
<p>Autorelease pool je vlastně jakýsi manažer paměti, který se stará právě o ty objekty, kterým zašleme <code>autorelease</code> namísto <code>release</code>. Všechny takovéto objeky se umístí do tohoto uložitě a fyzicky se uvolní až tehdy, když je uvolněn samotný objekt <code>NSAutoreleasePool</code>u. Všimli jste si, že v aplikaci používate <code>autorelease</code> ale přitom jste nikde instanci třídy <code>NSAutoreleasePool</code> nevytvářeli? Tak se podívejte do souboru <code>main.m</code> kteréhokoliv XCode projektu iPhonové aplikace. Autorelease poolů se ale vytváří bez našeho vědomí více. Application Kit automaticky vytváří pooly při začátku cyklu událostí (<em>event cycle</em>, či <em>event-loop</em>). Zde se zachytávají například události generované při kliknutí na prvek GUI a ostatní vnitřní záležitosti dějící se v aplikaci. Na konci tohoto <em>event-loop</em>u je pool zase automaticky uvolněn.</p>
<h3>Můžu si vytvořit své vlastní <em>samouvolňovací jezírko</em>?</h3>
<p>Samozřejmě, že ano. A v některých situacích je to dokonce velmi vhodné, až nezbytné. Při vývoji iPhonových aplikací je to typicky, když:</p>
<ol>
<li>používáme svá vlastní vlákna.<br />
Každé vlákno <strong>musí</strong> obsahovat autorelease pool. Nejčastěji si programátor vytvoří tento pool na začátku metody běžící ve vláknu a na konci metody pool zase uvolní. A pokud byste na to náhodou zapomněli nezoufejte, konzole vás na to upozorní hromadou krásných varování končících nějak podobně jako &#8222;object is just leaking&#8220;.</li>
<li>pokud v kódu máme cyklus vytvářející hodně pomocných objektů.<br />
Pokud máme cyklus a v každé iteraci potřebujeme vytvořit hodně pomocných objektů, může se hodit ušetřit paměť pomocí vytvoření autorelease poolu na začátku iterace cyklu a na konci iterace ho zase uvolnit. Docílíme tak uvolnění paměti hned jak ji skutečně nepotřebujeme, nikoliv akumulování a čekání až skončí event-loop případně jiný pool. Úplně ideální je uvolnit pool ne při každém průchodu, ale třeba jen v každé sté iteraci. To lze vyřešít jednoduchou <code>if</code> podmínkou.</li>
</ol>
<p>Při vytváření vlastních poolů platí pravidlo, že pool se uvolňuje ve stejné oblasti viditelnosti (<em>scope</em>) jako byl vytvořen, tedy vytvoříme-li ho na začátku metody, na konci ho uvolňíme, vytvoříme-li ho uvnitř cyklu, před koncem cyklu uvolníme atp.</p>
<h2>Doporučuji k přečtení</h2>
<p>Ačkoliv tento článek je docela obsáhlý, poskytuje jen tu nejnutnější množinu potřebných znalostí. Pokud chcete umět opravdu dobře zacházet s pamětí v Cocoa objective-c, doporučuji prostudovat si následující zdroje.</p>
<ul>
<li><a href="http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/ObjectiveC/Introduction/introObjectiveC.html">The Objective-C 2.0 Programming Language</a></li>
<li><a href="http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html">Memory Management Programming Guide for Cocoa</a></li>
</ul>
<p></p>]]></content:encoded>
			<wfw:commentRss>http://blog.urbasek.cz/cocoa-objective-c-a-prace-s-pameti/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
