<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="http://www.yifeiyang.net/styles/rss.css" type="text/css"?>

<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>YIFEIYANG</title>
	<atom:link href="http://www.yifeiyang.net/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.yifeiyang.net</link>
	<description>易飞扬的博客</description>
	<lastBuildDate>Mon, 16 Apr 2012 09:32:52 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<image>
<link>http://www.yifeiyang.net</link>
<url>http://www.yifeiyang.net/wp/wp-content/plugins/maxblogpress-favicon/icons/CARTOON5.JPG</url>
<title>YIFEIYANG</title>
</image>
		<item>
		<title>敏捷开发实践（3） &#8212; 培养敏捷开发团队</title>
		<link>http://www.yifeiyang.net/agile-development-practice-3/</link>
		<comments>http://www.yifeiyang.net/agile-development-practice-3/#comments</comments>
		<pubDate>Mon, 16 Apr 2012 00:57:00 +0000</pubDate>
		<dc:creator>yang</dc:creator>
				<category><![CDATA[敏捷开发]]></category>

		<guid isPermaLink="false">http://www.yifeiyang.net/%e6%95%8f%e6%8d%b7%e5%bc%80%e5%8f%91%e5%ae%9e%e8%b7%b5%ef%bc%883%ef%bc%89-%e5%9f%b9%e5%85%bb%e6%95%8f%e6%8d%b7%e5%bc%80%e5%8f%91%e5%9b%a2%e9%98%9f/</guid>
		<description><![CDATA[<div class="contents"> <dt> <a href="#sec1">Agile = 适应性 + 持续可能性</a> </dt> <dt> <a href="#sec2">软件开发以人为本</a> </dt> <dt> <a href="#sec3">怎样培养敏捷团队</a> </dt> <dd> <dl> <dt> <a href="#sec4">心态1：最初的目标 ≠ 最终目标</a> </dt> <dt> <a href="#sec5">心态2：组织的过程架构是可以改变的</a> </dt> <dt> <a href="#sec6">实践1：从小开始</a> </dt> <dt> <a href="#sec7">实践2：持续集成</a> </dt> </dl> </dd> </div>   <p style="text-align: center;"> <strong>敏捷开发实践（3） &#8212; 培养敏捷开发团队</strong> </p>  <h3><a name="sec1" id="sec1"></a>Agile = 适应性 + 持续可能性</h3>  <p class="first">敏捷开发的真谛是适应变化的情况，让开发持续，并改善其过程。它并不是单纯的用来缩短发布时间，提高工作效率，增强产品品质的手段，而是强调一种随机应变，持续改善的理念，一种过程思想。学习敏捷开发，首先考虑的是人。</p>   <h3><a name="sec2" id="sec2"></a>软件开发以人为本</h3>  <p class="first">软件是由人开发出来的，这是软件开发的大前提，不管你是用敏捷还是不用敏捷。</p>  <p>如果回到上世纪8、90年代，软件开发往往让人联想到个人英雄主义；那个时候，新兴的IT行业涌现出了类似求伯君，王江民，梁肇新等为大众所熟悉的高手。在他们身上凝聚了浓厚个人英雄色彩，并被许多那个时候成长起来的程序员所崇拜。但是，日趋庞大的软件项目和复杂需求需要更多人以标准化的软件工程方法去实现。这个过程科学而严谨，软件开发的每个步骤开始细分，程序员的工作定位开始清晰，随之而来，程序员的个人英雄色彩开始逐渐淡化，消失。</p>  <p>现在的一个大型软件项目已不再是依赖几个软件开发高手就能奏效的了。一个团队，一个协调一致的组织架构往往成了项目成功与否的关键因素。</p>  <p>敏捷开发正是一种注重“改造人”的开发手法，培养团队成员，构造成熟团队是敏捷的终极目标。而要培养优秀的敏捷团队， <strong>组织过程架构</strong>是其重中之重。</p>   <h3><a name="sec3" id="sec3"></a>怎样培养敏捷团队</h3>  <p class="first">每个敏捷团队都是不一样的，他们事前并没有统一的 <strong>组织过程架构</strong>。相反作为敏捷团队需要自己去发掘，整理，完善，最终建立适合自己的敏捷开发过程架构。这里从心态和实践两个方面来讨论。</p>  <h4><a name="sec4" id="sec4"></a>心态1：最初的目标 ≠ 最终目标</h4>  <p class="first">敏捷开发过程就是一个持续和反复的过程，其中有一个出现频度很高的词 &#8212; 改善；这就是说敏捷过程就是一个逐渐变大，逐渐成长的过程。通过不停的反复，实践，改善，最终完善产品自身和团队本体。</p>  <p>所以说项目开始时并不需要考虑所有的状况，指定终极的目标，以及理想的架构，Just Do it！仅此而已。</p>  <p>过程中发生问题怎么办？没关系，在迭代结束，回顾改善中发现问题，并在下个迭代中改善它既可。也即是说，「问题发生」本身不是问题，只要有应对问题的过程环节就OK。</p>   <h4><a name="sec5" id="sec5"></a>心态2：组织的过程架构是可以改变的</h4>  <p class="first">正如前面讲到的，敏捷开发是一种思想，他并没有给你划定条条框框，一切随实际情况而改变。</p>  <p>但是，我们往往不由自主的陷入体质和过程的怪圈 &#8212; 既然作为一个体系，一个过程管理架构，那么我们就要尽量维系它，遵循其起初制定，或其他地方吸收来的规则。而不管该架构形式是否适合自身的团队，一律照搬照抄。一旦出了问题，往往有「敏捷过程就是这样」，「架构没有问题」，「我们哪里用的不对而已」等等想法。不从组织过程架构中找问题是危险的。</p>  <p>组织过程架构是需要敏捷团队去建立和完善的，不管是从其他地方得到的经验，还是自己制定的规则，该体系都有可能在过程中出现不符合实际情况的问题。在迭代改善中发现它，在计划中完善它，在过程中改善它，是我们需要做的；而不要认为它是架构本身的问题而搁置它，不闻不问只会错上加错。</p>    <h4><a name="sec6" id="sec6"></a>实践1：从小开始</h4>  <p class="first">万事开头难，怎样才能减小开端的难度。从小的阶段目标做起，一边确认一边递进式的扩大作业范围。先是在小的规模下（个人或者是pair开发）体验敏捷开发的思想，然后逐渐扩大规模（团队或者组织内部）。随着规模的扩大，关系者的增加，影响范围也随之变大，需要考虑的事情变多，敏捷的难度也会伴随增加。这时，也是验证敏捷开发者应对变化能力的时候。</p>   <h4><a name="sec7" id="sec7"></a>实践2：持续集成</h4>  <p class="first">持续集成是指用自动化的工具验证成果物，并且每天至少一次。持续集成的目的是为了早起发现系统（除过软件成果物本身，整个敏捷架构过程也是该系统一部分）的问题，从而频繁的整合，检查。</p>  <h5>每日站立会议</h5>  <p>站会顾名思义就是站立着开会，一般会议持续10~15分钟，站久了累了就没有意义了。开站会的目的就是确认工作的进度状况，需要周知的事项，问题点等。基本上每天早晨实施的实例比较多。</p>  <div class="imagebox"> <p><a href="http://www.yifeiyang.net/images/agile/standingup.jpg"> <img src="http://www.yifeiyang.net/images/agile/standingup.jpg" alt="standingup" /></a> </p></div>  <p>站会是一种高效的沟通方式，作为工作开始的合意，问题点的共享等方面往往有意想不到的效果。</p>  <p>如果想更加紧密，频繁地整合敏捷系统，和早会对应，在下班前用5到10分开一下站立的“晚会”往往有更好的效果。这里，我们回顾每日工作的情况，检验本日的工作成果。通过“晚会”，我们可以：</p>  <ul> <li>强制在约定时间内停止自己的工作</li> <li>作为一天的回顾，营造「团队工作结束」的氛围</li> </ul>  <p>如果有加班的情况，在“晚会”上周知团队的其他成员。如果有早退的情况，可以在早会的时候给大家通知，有必要的情况下，可以调整“晚会”的开始时间点。</p>]]></description>
			<content:encoded><![CDATA[<div class="contents">
<dt> <a href="#sec1">Agile = 适应性 + 持续可能性</a> </dt>
<dt> <a href="#sec2">软件开发以人为本</a> </dt>
<dt> <a href="#sec3">怎样培养敏捷团队</a> </dt>
<dd>
<dl>
<dt> <a href="#sec4">心态1：最初的目标 ≠ 最终目标</a> </dt>
<dt> <a href="#sec5">心态2：组织的过程架构是可以改变的</a> </dt>
<dt> <a href="#sec6">实践1：从小开始</a> </dt>
<dt> <a href="#sec7">实践2：持续集成</a> </dt>
</dl>
</dd></div>
<p style="text-align: center;"> <strong>敏捷开发实践（3） &mdash; 培养敏捷开发团队</strong> </p>
<h3><a name="sec1" id="sec1"></a>Agile = 适应性 + 持续可能性</h3>
<p class="first">敏捷开发的真谛是适应变化的情况，让开发持续，并改善其过程。它并不是单纯的用来缩短发布时间，提高工作效率，增强产品品质的手段，而是强调一种随机应变，持续改善的理念，一种过程思想。学习敏捷开发，首先考虑的是人。</p>
<h3><a name="sec2" id="sec2"></a>软件开发以人为本</h3>
<p class="first">软件是由人开发出来的，这是软件开发的大前提，不管你是用敏捷还是不用敏捷。</p>
<p>如果回到上世纪8、90年代，软件开发往往让人联想到个人英雄主义；那个时候，新兴的IT行业涌现出了类似求伯君，王江民，梁肇新等为大众所熟悉的高手。在他们身上凝聚了浓厚个人英雄色彩，并被许多那个时候成长起来的程序员所崇拜。但是，日趋庞大的软件项目和复杂需求需要更多人以标准化的软件工程方法去实现。这个过程科学而严谨，软件开发的每个步骤开始细分，程序员的工作定位开始清晰，随之而来，程序员的个人英雄色彩开始逐渐淡化，消失。</p>
<p>现在的一个大型软件项目已不再是依赖几个软件开发高手就能奏效的了。一个团队，一个协调一致的组织架构往往成了项目成功与否的关键因素。</p>
<p>敏捷开发正是一种注重“改造人”的开发手法，培养团队成员，构造成熟团队是敏捷的终极目标。而要培养优秀的敏捷团队， <strong>组织过程架构</strong>是其重中之重。</p>
<h3><a name="sec3" id="sec3"></a>怎样培养敏捷团队</h3>
<p class="first">每个敏捷团队都是不一样的，他们事前并没有统一的 <strong>组织过程架构</strong>。相反作为敏捷团队需要自己去发掘，整理，完善，最终建立适合自己的敏捷开发过程架构。这里从心态和实践两个方面来讨论。</p>
<h4><a name="sec4" id="sec4"></a>心态1：最初的目标 ≠ 最终目标</h4>
<p class="first">敏捷开发过程就是一个持续和反复的过程，其中有一个出现频度很高的词 &mdash; 改善；这就是说敏捷过程就是一个逐渐变大，逐渐成长的过程。通过不停的反复，实践，改善，最终完善产品自身和团队本体。</p>
<p>所以说项目开始时并不需要考虑所有的状况，指定终极的目标，以及理想的架构，Just Do it！仅此而已。</p>
<p>过程中发生问题怎么办？没关系，在迭代结束，回顾改善中发现问题，并在下个迭代中改善它既可。也即是说，「问题发生」本身不是问题，只要有应对问题的过程环节就OK。</p>
<h4><a name="sec5" id="sec5"></a>心态2：组织的过程架构是可以改变的</h4>
<p class="first">正如前面讲到的，敏捷开发是一种思想，他并没有给你划定条条框框，一切随实际情况而改变。</p>
<p>但是，我们往往不由自主的陷入体质和过程的怪圈 &mdash; 既然作为一个体系，一个过程管理架构，那么我们就要尽量维系它，遵循其起初制定，或其他地方吸收来的规则。而不管该架构形式是否适合自身的团队，一律照搬照抄。一旦出了问题，往往有「敏捷过程就是这样」，「架构没有问题」，「我们哪里用的不对而已」等等想法。不从组织过程架构中找问题是危险的。</p>
<p>组织过程架构是需要敏捷团队去建立和完善的，不管是从其他地方得到的经验，还是自己制定的规则，该体系都有可能在过程中出现不符合实际情况的问题。在迭代改善中发现它，在计划中完善它，在过程中改善它，是我们需要做的；而不要认为它是架构本身的问题而搁置它，不闻不问只会错上加错。</p>
<h4><a name="sec6" id="sec6"></a>实践1：从小开始</h4>
<p class="first">万事开头难，怎样才能减小开端的难度。从小的阶段目标做起，一边确认一边递进式的扩大作业范围。先是在小的规模下（个人或者是pair开发）体验敏捷开发的思想，然后逐渐扩大规模（团队或者组织内部）。随着规模的扩大，关系者的增加，影响范围也随之变大，需要考虑的事情变多，敏捷的难度也会伴随增加。这时，也是验证敏捷开发者应对变化能力的时候。</p>
<h4><a name="sec7" id="sec7"></a>实践2：持续集成</h4>
<p class="first">持续集成是指用自动化的工具验证成果物，并且每天至少一次。持续集成的目的是为了早起发现系统（除过软件成果物本身，整个敏捷架构过程也是该系统一部分）的问题，从而频繁的整合，检查。</p>
<h5>每日站立会议</h5>
<p>站会顾名思义就是站立着开会，一般会议持续10~15分钟，站久了累了就没有意义了。开站会的目的就是确认工作的进度状况，需要周知的事项，问题点等。基本上每天早晨实施的实例比较多。</p>
<div class="imagebox">
<p><a href="http://www.yifeiyang.net/images/agile/standingup.jpg" rel="lightbox[477]"> <img src="http://www.yifeiyang.net/images/agile/standingup.jpg" alt="standingup" /></a> </p>
</div>
<p>站会是一种高效的沟通方式，作为工作开始的合意，问题点的共享等方面往往有意想不到的效果。</p>
<p>如果想更加紧密，频繁地整合敏捷系统，和早会对应，在下班前用5到10分开一下站立的“晚会”往往有更好的效果。这里，我们回顾每日工作的情况，检验本日的工作成果。通过“晚会”，我们可以：</p>
<ul>
<li>强制在约定时间内停止自己的工作</li>
<li>作为一天的回顾，营造「团队工作结束」的氛围</li>
</ul>
<p>如果有加班的情况，在“晚会”上周知团队的其他成员。如果有早退的情况，可以在早会的时候给大家通知，有必要的情况下，可以调整“晚会”的开始时间点。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.yifeiyang.net/agile-development-practice-3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>iPhone开发之深入浅出 (7) &#8212; ARC总结</title>
		<link>http://www.yifeiyang.net/development-of-the-iphone-simply-7/</link>
		<comments>http://www.yifeiyang.net/development-of-the-iphone-simply-7/#comments</comments>
		<pubDate>Wed, 28 Mar 2012 00:55:00 +0000</pubDate>
		<dc:creator>yang</dc:creator>
				<category><![CDATA[ARC]]></category>
		<category><![CDATA[深入浅出]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[嵌入式]]></category>

		<guid isPermaLink="false">http://www.yifeiyang.net/iphone%e5%bc%80%e5%8f%91%e4%b9%8b%e6%b7%b1%e5%85%a5%e6%b5%85%e5%87%ba-7-arc%e6%80%bb%e7%bb%93/</guid>
		<description><![CDATA[<div class="contents"><dt><a href="#sec1">内存管理基本原则</a> </dt><dt><a href="#sec2">所有权关键字</a> </dt><dt><a href="#sec3">ARC使用准则</a> </dt><dd><dl><dt><a href="#sec4">不能使用 retain/release/retainCount/autorelease</a> </dt><dt><a href="#sec5">不能使用 NSAllocateObject/NSDeallocateObject</a> </dt><dt><a href="#sec6">不能使用 NSZone</a> </dt><dt><a href="#sec7">不能明示调用dealloc</a> </dt><dt><a href="#sec8">内存管理相关的函数必须遵循命名规则</a> </dt><dt><a href="#sec9">使用@autoreleasepool代替NSAutoreleasePool</a> </dt><dt><a href="#sec10">Objective-C 对象不能作为C语言结构体（struct/union）的成员</a> </dt><dt><a href="#sec11">【id】与【void*】之间需要明示cast</a> </dt></dl></dd><dt><a href="#sec12">题外话</a> </dt><dd><dl><dt><a href="#sec13">Xcode 4.3带来的变化</a> </dt><dt><a href="#sec14">ARC 代码自动变换</a> </dt><dt><a href="#sec15">为什么iOS中没有GC</a> </dt></dl></dd></div>  <p style="text-align: center"><strong>iPhone开发之深入浅出 (7) — ARC总结</strong> </p>  <p>通过前面几篇文章的介绍，我想大家应该对ARC有了一个比较完整的理解。最后，我们来对ARC做一个总结，并把一些未涉及到的细节部分再深入讨论一下。</p>  <h3><a id="sec1" name="sec1"></a>内存管理基本原则</h3> <dl><dt><strong>内存管理的依循下面的基本原则</strong></dt><dd></dd></dl>  <ul>   <li>自己生成的对象，那么既是其持有者 </li>    <li>不是自己生成的对象，也可成为其持有者（一个对象可以被多个人持有） </li>    <li>如果不想持有对象的时候，必须释放其所有权 </li>    <li>不能释放已不再持有所有权的对象      <p>不管ARC有没有效，该原则始终存在。</p>   </li> </ul>  <h3><a id="sec2" name="sec2"></a>所有权关键字</h3>  <p class="first">从代码上看，有ARC的代码和没有ARC的代码区别就在下面的几个关键字。</p>  <p>类似 NSObject* 的对象类型，或者 id 类型<sup><a class="footref" href="#fn.1" name="fnr.1">1</a></sup>，当ARC有效的时候，根据具体情况，这些关键字必须要使用<sup><a class="footref" href="#fn.2" name="fnr.2">2</a></sup>。</p>  <ul>   <li>__strong </li>    <li>__weak </li>    <li>__unsafe_unretained </li>    <li>__autoreleasing      <p>__strong是默认的修饰符。</p>      <p>__weak修饰了一个自动nil的weak引用。</p>      <p>__unsafe_unretained声明了一个不会自动nil的weak引用。当变量被释放，那么它就变成了一个野指针了。</p>      <p>__autoreleasing 用来修饰一个声明为 (id *) 的函数的参数，当函数返回值时被释放。</p>   </li> </ul>  <p>接下来，我们结合下面ARC的使用准则，来看看一些使用ARC后的技术细节。</p>  <h3><a id="sec3" name="sec3"></a>ARC使用准则</h3>  <p class="first">为了比秒程序秒退的尴尬，ARC有效时，我们的代码必须遵循下面的准则。</p>  <ul>   <li>不能使用 retain/release/retainCount/autorelease </li>    <li>不能使用 NSAllocateObject/NSDeallocateObject </li>    <li>不能使用 NSZone </li>    <li>不能明示调用dealloc </li>    <li>内存管理相关的函数必须遵循命名规则 </li>    <li>使用@autoreleasepool代替NSAutoreleasePool </li>    <li>Objective-C 对象不能作为C语言结构体（struct/union）的成员 </li>    <li>【id】与【void*】之间需要明示cast </li> </ul>  <p>建议使用Objective-C的class来管理数据格式，来代替C语言的struct。不能隐式转换 id 和 void *。</p> <dl><dt><strong>让我们一个一个来分析</strong></dt><dd></dd></dl>  <h4><a id="sec4" name="sec4"></a>不能使用 retain/release/retainCount/autorelease</h4>  <p class="first">内存管理完全交给编译器去做，所以之前内存相关的函数(retain/release/retainCount/autorelease)不能出现在程序中。Apple的ARC文档中也有下面的说明。</p>  <blockquote>   <p class="quoted"><strong>ARC 有效后，不需要再次使用retain 和 release</strong></p> </blockquote>  <p>如果我们在程序中使用这些函数，经得到类似下面的编译错误信息。</p>  <pre class="example">    error: ARC forbids explicit message send of ’release’
         [o release];
          ^ ~~~~~~~</pre>

<h4><a id="sec5" name="sec5"></a>不能使用 NSAllocateObject/NSDeallocateObject</h4>

<p class="first">生成并持有一个Objective-C对象的时候，往往像下面一样使用NSObject的alloc接口函数。</p>

<pre class="example">    id obj = [NSObject alloc];</pre>

<p>实际上，如果我们看了GNUstep 中关于 alloc 的代码就会明白，实际他是使用 NSAllocateObject 来生成并持有对象实例的。换言之，ARC有效的时候，NSAllocateObject函数的调用也是禁止的。如果使用，也会遇到下面的编译错误。</p>

<pre class="example">    error: ’NSAllocateObject’ is unavailable:
        not available in automatic reference counting mode</pre>

<p>同样，对象释放时使用的 NSDeallocateObject 函数也不能使用。</p>

<h4><a id="sec6" name="sec6"></a>不能使用 NSZone</h4>

<p class="first">NSZone 是什么？NSZone 是为了防止内存碎片而导入的一项措施。Zone 是内存管理的基本单元，系统中管理复数的Zone。系统根据对象的使用目的，尺寸，分配其所属的Zone区域。以提高对象的访问效率，避免不必要的内存碎片。但是，现在的运行时系统（用编译开关 __OBJC2__ 指定的情况下）是不支持Zone概念的。所以，不管ARC是否有效，都不能使用 NSZone。</p>

<h4><a id="sec7" name="sec7"></a>不能明示调用dealloc</h4>

<p class="first">不管是否使用ARC，当对象被释放的时候，对象的dealloc函数被调用（就像是C++中对象的析构函数）。在该函数中，需要做一些内存释放的动作。比如，当对象中使用了malloc分配的C语言内存空间，那么dealloc中就需要像下面一样处理内存的释放。</p>

<div class="codebox">
  <table width="100%"><tbody>
      <tr>
        <td class="line_numbers">
          <pre>1
2
3
4</pre>
        </td>

        <td>
          <pre style="color: #f5deb3" class="src">- (<span class="type">void</span>) <span class="function-name">dealloc</span>
{
    free(buffer_);
}</pre>
        </td>
      </tr>

      <tr></tr>
    </tbody></table>
</div>

<p>又或者是注册的delegate对象，观察者对象需要被删除的时候，也是在dealloc函数中动作。</p>

<div class="codebox">
  <table width="100%"><tbody>
      <tr>
        <td class="line_numbers">
          <pre>1
2
3
4</pre>
        </td>

        <td>
          <pre style="color: #f5deb3" class="src">- (<span class="type">void</span>) <span class="function-name">dealloc</span>
{
    [[<span class="type">NSNotificationCenter</span> defaultCenter] removeObserver:<span class="keyword">self</span>];
}</pre>
        </td>
      </tr>

      <tr></tr>
    </tbody></table>
</div>

<p>如果在ARC无效的时候，我们还要像下面一样，调用父类对象的dealloc函数。</p>

<div class="codebox">
  <table width="100%"><tbody>
      <tr>
        <td class="line_numbers">
          <pre>1
2
3
4</pre>
        </td>

        <td>
          <pre style="color: #f5deb3" class="src">- (<span class="type">void</span>) <span class="function-name">dealloc</span>
{
    [<span class="keyword">super</span> dealloc];
}</pre>
        </td>
      </tr>

      <tr></tr>
    </tbody></table>
</div>

<p>但是当ARC有效的时候，[super dealloc];的调用已经被编译器自动执行，已经不需要我们明示调用了。如果你在代码中还这样写，难免遇到下面的错误。</p>

<pre class="example">    error: ARC forbids explicit message send of ’dealloc’
         [super dealloc];
          ^ ~~~~~~~</pre>

<h4><a id="sec8" name="sec8"></a>内存管理相关的函数必须遵循命名规则</h4>

<p class="first">在<a href="http://www.yifeiyang.net/development-of-the-iphone-simply-3/">iPhone开发之深入浅出 (3) — ARC之前世今生</a>中，我们知道如果是 alloc/new/copy/mutableCopy/init 开头的函数，需要将对象所有权返回给调用端。这条规则不管ARC是否有效都应该被遵守。只是 init 开头的函数比较特殊，他只在ARC下有要求，而且异常苛刻。</p>

<p>init 开始的函数只能返回id型，或者是该函数所属的类/父类的对象类型。基本上来说，init函数是针对alloc函数的返回值，做一些初始化处理，然后再将该对象返回。比如：</p>

<pre class="example">    id obj = [[NSObject alloc] init];</pre>

<p>再比如下面定义的函数就是不对的：</p>

<pre class="example">    - (void) initThisObject;</pre>

<p>需要是下面这样：</p>

<pre class="example">    - (id) initWithObject:(id)obj;</pre>

<p>另外，下面名为 initialize 的函数比较特殊，编译器将把它过滤掉，不按上面的规则处理。</p>

<h4><a id="sec9" name="sec9"></a>使用@autoreleasepool代替NSAutoreleasePool</h4>

<p class="first">在ARC之下，已经不能在代码中使用 NSAutoreleasePool，我们之前写 main.m 文件的时候，往往像下面这样写。</p>

<div class="codebox">
  <table width="100%"><tbody>
      <tr>
        <td class="line_numbers">
          <pre>1
2
3
4
5
6</pre>
        </td>

        <td>
          <pre style="color: #f5deb3" class="src">    <span class="type">int</span> <span class="function-name">main</span>(<span class="type">int</span> <span class="variable-name">argc</span>, <span class="type">char</span> *<span class="variable-name">argv</span>[]) {
    <span class="type">NSAutoreleasePool</span> * <span class="variable-name">pool</span> = [[<span class="type">NSAutoreleasePool</span> alloc] init];
    <span class="type">int</span> <span class="variable-name">retVal</span> = UIApplicationMain(argc, argv, <span class="constant">nil</span>, <span class="constant">nil</span>);
    [pool release];
    <span class="keyword">return</span> retVal;
}</pre>
        </td>
      </tr>

      <tr></tr>
    </tbody></table>
</div>

<p>而当ARC有效后，我们需要用@autoreleasepool代替NSAutoreleasePool。</p>

<div class="codebox">
  <table width="100%"><tbody>
      <tr>
        <td class="line_numbers">
          <pre>1
2
3
4
5
6</pre>
        </td>

        <td>
          <pre style="color: #f5deb3" class="src"><span class="type">int</span> <span class="function-name">main</span>(<span class="type">int</span> <span class="variable-name">argc</span>, <span class="type">char</span> *<span class="variable-name">argv</span>[])
{
    @autoreleasepool {
        <span class="keyword">return</span> UIApplicationMain(argc, argv, <span class="constant">nil</span>, <span class="type">NSStringFromClass</span>([<span class="type">AppDelegate</span> class]));
    }
}</pre>
        </td>
      </tr>

      <tr></tr>
    </tbody></table>
</div>

<p>当编译器看到 @autoreleasepool 定义的块后会自动生成 NSAutoreleasePool 对象，并将需要的对象放入 AutoReleasePool 中，当出方块的定义范围时，pool 中的对象将被释放。</p>

<h4><a id="sec10" name="sec10"></a>Objective-C 对象不能作为C语言结构体（struct/union）的成员</h4>

<p class="first">当我们设置ARC有效，并在C语言的结构体中定义Objective-C的对象时，将出现类似下面的编译错误。</p>

<div class="codebox">
  <table width="100%"><tbody>
      <tr>
        <td class="line_numbers">
          <pre>1
2
3</pre>
        </td>

        <td>
          <pre style="color: #f5deb3" class="src"><span class="keyword">struct</span> <span class="type">Data</span> {
    <span class="type">NSMutableArray</span> *<span class="variable-name">array</span>;
};</pre>
        </td>
      </tr>

      <tr></tr>
    </tbody></table>
</div>

<pre class="example">    error: ARC forbids Objective-C objs in structs or unions
         NSMutableArray *array;
                         ^</pre>

<p>由于 ARC 是将内存管理的细节委托给编译器来做，所以说编译器必须要管理对象的生命周期。而LLVM 3.0中不存在对单纯C语言构造体成员的内存管理方法。如果单纯是栈对象，利用进出栈原理，可以简单地维护对象的生命周期；而结构体是不行的，简单地理解，结构体没有析构函数，编译器自身不能自动释放其内部的 Objective-C 对象。</p>

<p>当我们必须在C语言的结构体中放入 Objective-C 对象的时候，可以使用 void* 转型，或者使用 __unsafe_unretained 关键字。比如下面：</p>

<div class="codebox">
  <table width="100%"><tbody>
      <tr>
        <td class="line_numbers">
          <pre>1
2
3</pre>
        </td>

        <td>
          <pre style="color: #f5deb3" class="src"><span class="keyword">struct</span> <span class="type">Data</span> {
    NSMutableArray __unsafe_unretained *array;
};</pre>
        </td>
      </tr>

      <tr></tr>
    </tbody></table>
</div>

<p>这样一来，该内存信息不在编译器内存管理对象内，仅仅是使用而已，没有对象的持有权。当然，对象所有权的持有者需要明确的管理他与该结构体的交互，不要引起不必要的错误<sup><a class="footref" href="#fn.3" name="fnr.3">3</a></sup>。</p>

<h4><a id="sec11" name="sec11"></a>【id】与【void*】之间需要明示cast</h4>

<p class="first">ARC 有效的时候，由于编译器帮我们做了内存管理的工作，所以我们不需要太担心。但是当与 ARC 管理以外的对象类型交互的时候，就需要特殊的转型关键字，来决定所有权的归属问题。</p>

<p>主要的转型关键字是:</p>

<table class="muse-table" border="2" cellpadding="5"><thead>
    <tr>
      <th>关键字</th>

      <th>解释</th>
    </tr>
  </thead><tbody>
    <tr>
      <td>__bridge</td>

      <td>单纯的类型转换，没有进行所有权的转移</td>
    </tr>

    <tr>
      <td>__bridge_retained</td>

      <td>类型转换是伴随所有权传递，转换前后变量都持有对象的所有权</td>
    </tr>

    <tr>
      <td>__bridge_transfer</td>

      <td>类型转换伴随所有权转移，被转换变量将失去对象的所有权</td>
    </tr>
  </tbody></table>

<p>当我们在 Core Foundation 对象类型与 Objective-C 对象类型之间切换的时候，需要把握下面的因素：</p>

<ul>
  <li>明确被转换类型是否是 ARC 管理的对象 
    <ul>
      <li>Core Foundation 对象类型不在 ARC 管理范畴内 </li>

      <li>Cocoa Framework::Foundation 对象类型（即一般使用到的Objectie-C对象类型）在 ARC 的管理范畴内 </li>
    </ul>
  </li>

  <li>如果不在 ARC 管理范畴内的对象，那么要清楚 release 的责任应该是谁 </li>

  <li>各种对象的生命周期是怎样的 </li>
</ul>

<h3><a id="sec12" name="sec12"></a>题外话</h3>

<h4><a id="sec13" name="sec13"></a>Xcode 4.3带来的变化</h4>

<p class="first">最近随着 iOS 5.1 的推出，Xcode也推出了4.3版本。在该版本下，ARC 有效时的属性(@property) 定义的时候，如果不明确指定所有权关键字，那么缺省的就是 strong。而在 Xcode4.2 中，即使 strong 也要显示指定。</p>

<p>在 Xcode4.2 的时候，针对下面的代码，</p>

<div class="codebox">
  <table width="100%"><tbody>
      <tr>
        <td class="line_numbers">
          <pre>1
2
3
4
5
6
7</pre>
        </td>

        <td>
          <pre style="color: #f5deb3" class="src"><span class="comment-delimiter">// </span><span class="comment">ARC 无效
</span>@property (nonatomic, retain) <span class="type">NSString</span> *<span class="variable-name">string</span>;

<span class="comment-delimiter">// </span><span class="comment">---&#62;
</span>
<span class="comment-delimiter">// </span><span class="comment">ARC 有效
</span>@property (nonatomic, strong) <span class="type">NSString</span> *<span class="variable-name">string</span>;</pre>
        </td>
      </tr>

      <tr></tr>
    </tbody></table>
</div>

<p>而在 Xcode 4.3 中，我们可以这么做，</p>

<div class="codebox">
  <table width="100%"><tbody>
      <tr>
        <td class="line_numbers">
          <pre>1
2
3
4
5
6
7</pre>
        </td>

        <td>
          <pre style="color: #f5deb3" class="src"><span class="comment-delimiter">// </span><span class="comment">ARC 无效
</span>@property (nonatomic, retain) <span class="type">NSString</span> *<span class="variable-name">string</span>;

<span class="comment-delimiter">// </span><span class="comment">---&#62;
</span>
<span class="comment-delimiter">// </span><span class="comment">ARC 有效
</span>@property (nonatomic) <span class="type">NSString</span> *<span class="variable-name">string</span>;</pre>
        </td>
      </tr>

      <tr></tr>
    </tbody></table>
</div>

<h4><a id="sec14" name="sec14"></a>ARC 代码自动变换</h4>

<p class="first">另外，Xcode 4.2开始，增加了旧代码向 ARC 代码自动转换的功能。有兴趣的朋友可以试试。位置是：</p>

<blockquote>
  <p class="quoted">Edit-&#62;Refactor-&#62;Convert to Objective-C ARC…</p>
</blockquote>

<h4><a id="sec15" name="sec15"></a>为什么iOS中没有GC</h4>

<p class="first">我们已经知道ARC并不是GC（垃圾回收）了，那么，为什么iOS中不支持该机能呢？还特意搞出个ARC来。以下是我的分析：</p>

<ul>
  <li>消耗CPU时间的处理尽量避免，以节约电池电量 </li>

  <li>GC执行的后，会停掉运行时库；这是最大的心结 </li>

  <li>嵌入式设备本身内存就不是很大，如果GC不停的在后台运行，执行的频率会很高，严重影响性能 
    <ul>
      <li>UI动画处理是iOS的一大卖点，而有了GC后可能会引起不必要的性能损失 </li>
    </ul>
  </li>
</ul>

<hr />

<p class="footnote"><a class="footnum" href="#fnr.1" name="fn.1">1.</a> 关于Objective-C对象的解释，可以参考<a href="http://www.yifeiyang.net/iphone-development-introduction-7-from-the-c-c-language-to-objective-c-language/">iPhone开发入门（7）— 从C/C++语言到Objective-C语言</a>。</p>

<p class="footnote"><a class="footnum" href="#fnr.2" name="fn.2">2.</a> 当然，如果你不写，编译器会用缺省的值代替。具体见<a href="http://www.yifeiyang.net/development-of-the-iphone-simply-3/">iPhone开发之深入浅出 (3) — ARC之前世今生</a>中的描述。</p>

<p class="footnote"><a class="footnum" href="#fnr.3" name="fn.3">3.</a> 关于这一点，可以参考<a href="http://www.yifeiyang.net/development-of-the-iphone-simply-1/">iPhone开发之深入浅出 (1) — ARC是什么</a> 一文，明白为什么 __unsafe_unretained 是危险的。</p>]]></description>
			<content:encoded><![CDATA[<div class="contents">
<dt><a href="#sec1">内存管理基本原则</a> </dt>
<dt><a href="#sec2">所有权关键字</a> </dt>
<dt><a href="#sec3">ARC使用准则</a> </dt>
<dd>
<dl>
<dt><a href="#sec4">不能使用 retain/release/retainCount/autorelease</a> </dt>
<dt><a href="#sec5">不能使用 NSAllocateObject/NSDeallocateObject</a> </dt>
<dt><a href="#sec6">不能使用 NSZone</a> </dt>
<dt><a href="#sec7">不能明示调用dealloc</a> </dt>
<dt><a href="#sec8">内存管理相关的函数必须遵循命名规则</a> </dt>
<dt><a href="#sec9">使用@autoreleasepool代替NSAutoreleasePool</a> </dt>
<dt><a href="#sec10">Objective-C 对象不能作为C语言结构体（struct/union）的成员</a> </dt>
<dt><a href="#sec11">【id】与【void*】之间需要明示cast</a> </dt>
</dl>
</dd>
<dt><a href="#sec12">题外话</a> </dt>
<dd>
<dl>
<dt><a href="#sec13">Xcode 4.3带来的变化</a> </dt>
<dt><a href="#sec14">ARC 代码自动变换</a> </dt>
<dt><a href="#sec15">为什么iOS中没有GC</a> </dt>
</dl>
</dd>
</div>
<p style="text-align: center"><strong>iPhone开发之深入浅出 (7) — ARC总结</strong> </p>
<p>通过前面几篇文章的介绍，我想大家应该对ARC有了一个比较完整的理解。最后，我们来对ARC做一个总结，并把一些未涉及到的细节部分再深入讨论一下。</p>
<h3><a id="sec1" name="sec1"></a>内存管理基本原则</h3>
<dl>
<dt><strong>内存管理的依循下面的基本原则</strong></dt>
<dd></dd>
</dl>
<ul>
<li>自己生成的对象，那么既是其持有者 </li>
<li>不是自己生成的对象，也可成为其持有者（一个对象可以被多个人持有） </li>
<li>如果不想持有对象的时候，必须释放其所有权 </li>
<li>不能释放已不再持有所有权的对象
<p>不管ARC有没有效，该原则始终存在。</p>
</li>
</ul>
<h3><a id="sec2" name="sec2"></a>所有权关键字</h3>
<p class="first">从代码上看，有ARC的代码和没有ARC的代码区别就在下面的几个关键字。</p>
<p>类似 NSObject* 的对象类型，或者 id 类型<sup><a class="footref" href="#fn.1" name="fnr.1">1</a></sup>，当ARC有效的时候，根据具体情况，这些关键字必须要使用<sup><a class="footref" href="#fn.2" name="fnr.2">2</a></sup>。</p>
<ul>
<li>__strong </li>
<li>__weak </li>
<li>__unsafe_unretained </li>
<li>__autoreleasing
<p>__strong是默认的修饰符。</p>
<p>__weak修饰了一个自动nil的weak引用。</p>
<p>__unsafe_unretained声明了一个不会自动nil的weak引用。当变量被释放，那么它就变成了一个野指针了。</p>
<p>__autoreleasing 用来修饰一个声明为 (id *) 的函数的参数，当函数返回值时被释放。</p>
</li>
</ul>
<p>接下来，我们结合下面ARC的使用准则，来看看一些使用ARC后的技术细节。</p>
<h3><a id="sec3" name="sec3"></a>ARC使用准则</h3>
<p class="first">为了比秒程序秒退的尴尬，ARC有效时，我们的代码必须遵循下面的准则。</p>
<ul>
<li>不能使用 retain/release/retainCount/autorelease </li>
<li>不能使用 NSAllocateObject/NSDeallocateObject </li>
<li>不能使用 NSZone </li>
<li>不能明示调用dealloc </li>
<li>内存管理相关的函数必须遵循命名规则 </li>
<li>使用@autoreleasepool代替NSAutoreleasePool </li>
<li>Objective-C 对象不能作为C语言结构体（struct/union）的成员 </li>
<li>【id】与【void*】之间需要明示cast </li>
</ul>
<p>建议使用Objective-C的class来管理数据格式，来代替C语言的struct。不能隐式转换 id 和 void *。</p>
<dl>
<dt><strong>让我们一个一个来分析</strong></dt>
<dd></dd>
</dl>
<h4><a id="sec4" name="sec4"></a>不能使用 retain/release/retainCount/autorelease</h4>
<p class="first">内存管理完全交给编译器去做，所以之前内存相关的函数(retain/release/retainCount/autorelease)不能出现在程序中。Apple的ARC文档中也有下面的说明。</p>
<blockquote><p class="quoted"><strong>ARC 有效后，不需要再次使用retain 和 release</strong></p>
</blockquote>
<p>如果我们在程序中使用这些函数，经得到类似下面的编译错误信息。</p>
<pre class="example">    error: ARC forbids explicit message send of ’release’
         [o release];
          ^ ~~~~~~~</pre>
<h4><a id="sec5" name="sec5"></a>不能使用 NSAllocateObject/NSDeallocateObject</h4>
<p class="first">生成并持有一个Objective-C对象的时候，往往像下面一样使用NSObject的alloc接口函数。</p>
<pre class="example">    id obj = [NSObject alloc];</pre>
<p>实际上，如果我们看了GNUstep 中关于 alloc 的代码就会明白，实际他是使用 NSAllocateObject 来生成并持有对象实例的。换言之，ARC有效的时候，NSAllocateObject函数的调用也是禁止的。如果使用，也会遇到下面的编译错误。</p>
<pre class="example">    error: ’NSAllocateObject’ is unavailable:
        not available in automatic reference counting mode</pre>
<p>同样，对象释放时使用的 NSDeallocateObject 函数也不能使用。</p>
<h4><a id="sec6" name="sec6"></a>不能使用 NSZone</h4>
<p class="first">NSZone 是什么？NSZone 是为了防止内存碎片而导入的一项措施。Zone 是内存管理的基本单元，系统中管理复数的Zone。系统根据对象的使用目的，尺寸，分配其所属的Zone区域。以提高对象的访问效率，避免不必要的内存碎片。但是，现在的运行时系统（用编译开关 __OBJC2__ 指定的情况下）是不支持Zone概念的。所以，不管ARC是否有效，都不能使用 NSZone。</p>
<h4><a id="sec7" name="sec7"></a>不能明示调用dealloc</h4>
<p class="first">不管是否使用ARC，当对象被释放的时候，对象的dealloc函数被调用（就像是C++中对象的析构函数）。在该函数中，需要做一些内存释放的动作。比如，当对象中使用了malloc分配的C语言内存空间，那么dealloc中就需要像下面一样处理内存的释放。</p>
<div class="codebox">
<table width="100%">
<tbody>
<tr>
<td class="line_numbers">
<pre>1
2
3
4</pre>
</td>
<td>
<pre style="color: #f5deb3" class="src">- (<span class="type">void</span>) <span class="function-name">dealloc</span>
{
    free(buffer_);
}</pre>
</td>
</tr>
<tr></tr>
</tbody>
</table>
</div>
<p>又或者是注册的delegate对象，观察者对象需要被删除的时候，也是在dealloc函数中动作。</p>
<div class="codebox">
<table width="100%">
<tbody>
<tr>
<td class="line_numbers">
<pre>1
2
3
4</pre>
</td>
<td>
<pre style="color: #f5deb3" class="src">- (<span class="type">void</span>) <span class="function-name">dealloc</span>
{
    [[<span class="type">NSNotificationCenter</span> defaultCenter] removeObserver:<span class="keyword">self</span>];
}</pre>
</td>
</tr>
<tr></tr>
</tbody>
</table>
</div>
<p>如果在ARC无效的时候，我们还要像下面一样，调用父类对象的dealloc函数。</p>
<div class="codebox">
<table width="100%">
<tbody>
<tr>
<td class="line_numbers">
<pre>1
2
3
4</pre>
</td>
<td>
<pre style="color: #f5deb3" class="src">- (<span class="type">void</span>) <span class="function-name">dealloc</span>
{
    [<span class="keyword">super</span> dealloc];
}</pre>
</td>
</tr>
<tr></tr>
</tbody>
</table>
</div>
<p>但是当ARC有效的时候，[super dealloc];的调用已经被编译器自动执行，已经不需要我们明示调用了。如果你在代码中还这样写，难免遇到下面的错误。</p>
<pre class="example">    error: ARC forbids explicit message send of ’dealloc’
         [super dealloc];
          ^ ~~~~~~~</pre>
<h4><a id="sec8" name="sec8"></a>内存管理相关的函数必须遵循命名规则</h4>
<p class="first">在<a href="http://www.yifeiyang.net/development-of-the-iphone-simply-3/">iPhone开发之深入浅出 (3) — ARC之前世今生</a>中，我们知道如果是 alloc/new/copy/mutableCopy/init 开头的函数，需要将对象所有权返回给调用端。这条规则不管ARC是否有效都应该被遵守。只是 init 开头的函数比较特殊，他只在ARC下有要求，而且异常苛刻。</p>
<p>init 开始的函数只能返回id型，或者是该函数所属的类/父类的对象类型。基本上来说，init函数是针对alloc函数的返回值，做一些初始化处理，然后再将该对象返回。比如：</p>
<pre class="example">    id obj = [[NSObject alloc] init];</pre>
<p>再比如下面定义的函数就是不对的：</p>
<pre class="example">    - (void) initThisObject;</pre>
<p>需要是下面这样：</p>
<pre class="example">    - (id) initWithObject:(id)obj;</pre>
<p>另外，下面名为 initialize 的函数比较特殊，编译器将把它过滤掉，不按上面的规则处理。</p>
<h4><a id="sec9" name="sec9"></a>使用@autoreleasepool代替NSAutoreleasePool</h4>
<p class="first">在ARC之下，已经不能在代码中使用 NSAutoreleasePool，我们之前写 main.m 文件的时候，往往像下面这样写。</p>
<div class="codebox">
<table width="100%">
<tbody>
<tr>
<td class="line_numbers">
<pre>1
2
3
4
5
6</pre>
</td>
<td>
<pre style="color: #f5deb3" class="src">    <span class="type">int</span> <span class="function-name">main</span>(<span class="type">int</span> <span class="variable-name">argc</span>, <span class="type">char</span> *<span class="variable-name">argv</span>[]) {
    <span class="type">NSAutoreleasePool</span> * <span class="variable-name">pool</span> = [[<span class="type">NSAutoreleasePool</span> alloc] init];
    <span class="type">int</span> <span class="variable-name">retVal</span> = UIApplicationMain(argc, argv, <span class="constant">nil</span>, <span class="constant">nil</span>);
    [pool release];
    <span class="keyword">return</span> retVal;
}</pre>
</td>
</tr>
<tr></tr>
</tbody>
</table>
</div>
<p>而当ARC有效后，我们需要用@autoreleasepool代替NSAutoreleasePool。</p>
<div class="codebox">
<table width="100%">
<tbody>
<tr>
<td class="line_numbers">
<pre>1
2
3
4
5
6</pre>
</td>
<td>
<pre style="color: #f5deb3" class="src"><span class="type">int</span> <span class="function-name">main</span>(<span class="type">int</span> <span class="variable-name">argc</span>, <span class="type">char</span> *<span class="variable-name">argv</span>[])
{
    @autoreleasepool {
        <span class="keyword">return</span> UIApplicationMain(argc, argv, <span class="constant">nil</span>, <span class="type">NSStringFromClass</span>([<span class="type">AppDelegate</span> class]));
    }
}</pre>
</td>
</tr>
<tr></tr>
</tbody>
</table>
</div>
<p>当编译器看到 @autoreleasepool 定义的块后会自动生成 NSAutoreleasePool 对象，并将需要的对象放入 AutoReleasePool 中，当出方块的定义范围时，pool 中的对象将被释放。</p>
<h4><a id="sec10" name="sec10"></a>Objective-C 对象不能作为C语言结构体（struct/union）的成员</h4>
<p class="first">当我们设置ARC有效，并在C语言的结构体中定义Objective-C的对象时，将出现类似下面的编译错误。</p>
<div class="codebox">
<table width="100%">
<tbody>
<tr>
<td class="line_numbers">
<pre>1
2
3</pre>
</td>
<td>
<pre style="color: #f5deb3" class="src"><span class="keyword">struct</span> <span class="type">Data</span> {
    <span class="type">NSMutableArray</span> *<span class="variable-name">array</span>;
};</pre>
</td>
</tr>
<tr></tr>
</tbody>
</table>
</div>
<pre class="example">    error: ARC forbids Objective-C objs in structs or unions
         NSMutableArray *array;
                         ^</pre>
<p>由于 ARC 是将内存管理的细节委托给编译器来做，所以说编译器必须要管理对象的生命周期。而LLVM 3.0中不存在对单纯C语言构造体成员的内存管理方法。如果单纯是栈对象，利用进出栈原理，可以简单地维护对象的生命周期；而结构体是不行的，简单地理解，结构体没有析构函数，编译器自身不能自动释放其内部的 Objective-C 对象。</p>
<p>当我们必须在C语言的结构体中放入 Objective-C 对象的时候，可以使用 void* 转型，或者使用 __unsafe_unretained 关键字。比如下面：</p>
<div class="codebox">
<table width="100%">
<tbody>
<tr>
<td class="line_numbers">
<pre>1
2
3</pre>
</td>
<td>
<pre style="color: #f5deb3" class="src"><span class="keyword">struct</span> <span class="type">Data</span> {
    NSMutableArray __unsafe_unretained *array;
};</pre>
</td>
</tr>
<tr></tr>
</tbody>
</table>
</div>
<p>这样一来，该内存信息不在编译器内存管理对象内，仅仅是使用而已，没有对象的持有权。当然，对象所有权的持有者需要明确的管理他与该结构体的交互，不要引起不必要的错误<sup><a class="footref" href="#fn.3" name="fnr.3">3</a></sup>。</p>
<h4><a id="sec11" name="sec11"></a>【id】与【void*】之间需要明示cast</h4>
<p class="first">ARC 有效的时候，由于编译器帮我们做了内存管理的工作，所以我们不需要太担心。但是当与 ARC 管理以外的对象类型交互的时候，就需要特殊的转型关键字，来决定所有权的归属问题。</p>
<p>主要的转型关键字是:</p>
<table class="muse-table" border="2" cellpadding="5">
<thead>
<tr>
<th>关键字</th>
<th>解释</th>
</tr>
</thead>
<tbody>
<tr>
<td>__bridge</td>
<td>单纯的类型转换，没有进行所有权的转移</td>
</tr>
<tr>
<td>__bridge_retained</td>
<td>类型转换是伴随所有权传递，转换前后变量都持有对象的所有权</td>
</tr>
<tr>
<td>__bridge_transfer</td>
<td>类型转换伴随所有权转移，被转换变量将失去对象的所有权</td>
</tr>
</tbody>
</table>
<p>当我们在 Core Foundation 对象类型与 Objective-C 对象类型之间切换的时候，需要把握下面的因素：</p>
<ul>
<li>明确被转换类型是否是 ARC 管理的对象
<ul>
<li>Core Foundation 对象类型不在 ARC 管理范畴内 </li>
<li>Cocoa Framework::Foundation 对象类型（即一般使用到的Objectie-C对象类型）在 ARC 的管理范畴内 </li>
</ul>
</li>
<li>如果不在 ARC 管理范畴内的对象，那么要清楚 release 的责任应该是谁 </li>
<li>各种对象的生命周期是怎样的 </li>
</ul>
<h3><a id="sec12" name="sec12"></a>题外话</h3>
<h4><a id="sec13" name="sec13"></a>Xcode 4.3带来的变化</h4>
<p class="first">最近随着 iOS 5.1 的推出，Xcode也推出了4.3版本。在该版本下，ARC 有效时的属性(@property) 定义的时候，如果不明确指定所有权关键字，那么缺省的就是 strong。而在 Xcode4.2 中，即使 strong 也要显示指定。</p>
<p>在 Xcode4.2 的时候，针对下面的代码，</p>
<div class="codebox">
<table width="100%">
<tbody>
<tr>
<td class="line_numbers">
<pre>1
2
3
4
5
6
7</pre>
</td>
<td>
<pre style="color: #f5deb3" class="src"><span class="comment-delimiter">// </span><span class="comment">ARC 无效
</span>@property (nonatomic, retain) <span class="type">NSString</span> *<span class="variable-name">string</span>;

<span class="comment-delimiter">// </span><span class="comment">---&gt;
</span>
<span class="comment-delimiter">// </span><span class="comment">ARC 有效
</span>@property (nonatomic, strong) <span class="type">NSString</span> *<span class="variable-name">string</span>;</pre>
</td>
</tr>
<tr></tr>
</tbody>
</table>
</div>
<p>而在 Xcode 4.3 中，我们可以这么做，</p>
<div class="codebox">
<table width="100%">
<tbody>
<tr>
<td class="line_numbers">
<pre>1
2
3
4
5
6
7</pre>
</td>
<td>
<pre style="color: #f5deb3" class="src"><span class="comment-delimiter">// </span><span class="comment">ARC 无效
</span>@property (nonatomic, retain) <span class="type">NSString</span> *<span class="variable-name">string</span>;

<span class="comment-delimiter">// </span><span class="comment">---&gt;
</span>
<span class="comment-delimiter">// </span><span class="comment">ARC 有效
</span>@property (nonatomic) <span class="type">NSString</span> *<span class="variable-name">string</span>;</pre>
</td>
</tr>
<tr></tr>
</tbody>
</table>
</div>
<h4><a id="sec14" name="sec14"></a>ARC 代码自动变换</h4>
<p class="first">另外，Xcode 4.2开始，增加了旧代码向 ARC 代码自动转换的功能。有兴趣的朋友可以试试。位置是：</p>
<blockquote>
<p class="quoted">Edit-&gt;Refactor-&gt;Convert to Objective-C ARC…</p>
</blockquote>
<h4><a id="sec15" name="sec15"></a>为什么iOS中没有GC</h4>
<p class="first">我们已经知道ARC并不是GC（垃圾回收）了，那么，为什么iOS中不支持该机能呢？还特意搞出个ARC来。以下是我的分析：</p>
<ul>
<li>消耗CPU时间的处理尽量避免，以节约电池电量 </li>
<li>GC执行的后，会停掉运行时库；这是最大的心结 </li>
<li>嵌入式设备本身内存就不是很大，如果GC不停的在后台运行，执行的频率会很高，严重影响性能
<ul>
<li>UI动画处理是iOS的一大卖点，而有了GC后可能会引起不必要的性能损失 </li>
</ul>
</li>
</ul>
<hr />
<p class="footnote"><a class="footnum" href="#fnr.1" name="fn.1">1.</a> 关于Objective-C对象的解释，可以参考<a href="http://www.yifeiyang.net/iphone-development-introduction-7-from-the-c-c-language-to-objective-c-language/">iPhone开发入门（7）— 从C/C++语言到Objective-C语言</a>。</p>
<p class="footnote"><a class="footnum" href="#fnr.2" name="fn.2">2.</a> 当然，如果你不写，编译器会用缺省的值代替。具体见<a href="http://www.yifeiyang.net/development-of-the-iphone-simply-3/">iPhone开发之深入浅出 (3) — ARC之前世今生</a>中的描述。</p>
<p class="footnote"><a class="footnum" href="#fnr.3" name="fn.3">3.</a> 关于这一点，可以参考<a href="http://www.yifeiyang.net/development-of-the-iphone-simply-1/">iPhone开发之深入浅出 (1) — ARC是什么</a> 一文，明白为什么 __unsafe_unretained 是危险的。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.yifeiyang.net/development-of-the-iphone-simply-7/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>iPhone开发之深入浅出 (6) &#8212; ARC之对象转型</title>
		<link>http://www.yifeiyang.net/development-of-the-iphone-simply-6/</link>
		<comments>http://www.yifeiyang.net/development-of-the-iphone-simply-6/#comments</comments>
		<pubDate>Sat, 24 Mar 2012 03:24:00 +0000</pubDate>
		<dc:creator>yang</dc:creator>
				<category><![CDATA[ARC]]></category>
		<category><![CDATA[深入浅出]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[iPad]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Objective-C]]></category>

		<guid isPermaLink="false">http://www.yifeiyang.net/iphone%e5%bc%80%e5%8f%91%e4%b9%8b%e6%b7%b1%e5%85%a5%e6%b5%85%e5%87%ba-6-arc%e4%b9%8b%e5%af%b9%e8%b1%a1%e8%bd%ac%e5%9e%8b/</guid>
		<description><![CDATA[<div class="contents"><dt><a href="#sec1">引子</a> </dt><dt><a href="#sec2">__bridge</a> </dt><dd><dl><dt><a href="#sec3">__bridge_retained</a> </dt><dt><a href="#sec4">__bridge_transfer</a> </dt></dl></dd><dt><a href="#sec5">Toll-Free bridged</a> </dt><dt><a href="#sec6">总结</a> </dt></div>  <p style="text-align: center"><strong>iPhone开发之深入浅出 (6) — ARC之对象转型</strong> </p>  <p>自 Xcode4.2 开始导入ARC机制后，为了支持对象间的转型，Apple又增加了许多转型用的关键字。这一讲我们就来了解其用法，以及产生的理由。</p>  
<h3><a id="sec1" name="sec1"></a>引子</h3>  <p class="first">我们先来看一下ARC无效的时候，我们写id类型转void*类型的写法：</p>  <div class="codebox">   <table width="100%"><tbody>       <tr>         <td class="line_numbers">           <pre>1
2</pre>
        </td>

        <td>
          <pre style="color: #f5deb3" class="src"><span class="type">id</span> <span class="variable-name">obj</span> = [[<span class="type">NSObject</span> alloc] init];
<span class="type">void</span> *<span class="variable-name">p</span> = obj;</pre>
        </td>
      </tr>

      <tr></tr>
    </tbody></table>
</div>

<p>反过来，当把void*对象变回id类型时，只是简单地如下来写，</p>

<div class="codebox">
  <table width="100%"><tbody>
      <tr>
        <td class="line_numbers">
          <pre>1
2</pre>
        </td>

        <td>
          <pre style="color: #f5deb3" class="src"><span class="type">id</span> <span class="variable-name">obj</span> = p;
[obj release];</pre>
        </td>
      </tr>

      <tr></tr>
    </tbody></table>
</div>

<p>但是上面的代码在ARC有效时，就有了下面的错误：</p>

<pre class="example">    error: implicit conversion of an Objective-C pointer
        to ’void *’ is disallowed with ARC
        void *p = obj;
                  ^

    error: implicit conversion of a non-Objective-C pointer
        type ’void *’ to ’id’ is disallowed with ARC
        id o = p;
                ^</pre>

<h3><a id="sec2" name="sec2"></a>__bridge</h3>

<p class="first">为了解决这一问题，我们使用 <strong>__bridge</strong> 关键字来实现id类型与void*类型的相互转换。看下面的例子。</p>

<div class="codebox">
  <table width="100%"><tbody>
      <tr>
        <td class="line_numbers">
          <pre>1
2
3
4
5</pre>
        </td>

        <td>
          <pre style="color: #f5deb3" class="src"><span class="type">id</span> <span class="variable-name">obj</span> = [[<span class="type">NSObject</span> alloc] init];

<span class="type">void</span> *<span class="variable-name">p</span> = (__bridge <span class="type">void</span> *)obj;

<span class="type">id</span> <span class="variable-name">o</span> = (__bridge <span class="type">id</span>)p;</pre>
        </td>
      </tr>

      <tr></tr>
    </tbody></table>
</div>

<p>将Objective-C的对象类型用 __bridge 转换为 void* 类型和使用 __unsafe_unretained 关键字修饰的变量是一样的。被代入对象的所有者需要明确对象生命周期的管理，不要出现异常访问的问题。</p>

<p>除过 __bridge 以外，还有两个 __bridge 相关的类型转换关键字：</p>

<ul>
  <li>__bridge_retained </li>

  <li>__bridge_transfer </li>
</ul>

<p>接下来，我们将看看这两个关键字的区别。</p>

<h4><a id="sec3" name="sec3"></a>__bridge_retained</h4>

<p class="first">先来看使用 __bridge_retained 关键字的例子程序：</p>

<div class="codebox">
  <table width="100%"><tbody>
      <tr>
        <td class="line_numbers">
          <pre>1
2
3</pre>
        </td>

        <td>
          <pre style="color: #f5deb3" class="src"><span class="type">id</span> <span class="variable-name">obj</span> = [[<span class="type">NSObject</span> alloc] init];

<span class="type">void</span> *<span class="variable-name">p</span> = (__bridge_retained <span class="type">void</span> *)obj;</pre>
        </td>
      </tr>

      <tr></tr>
    </tbody></table>
</div>

<p>从名字上我们应该能理解其意义：类型被转换时，其对象的所有权也将被变换后变量所持有。如果不是ARC代码，类似下面的实现：</p>

<div class="codebox">
  <table width="100%"><tbody>
      <tr>
        <td class="line_numbers">
          <pre>1
2
3
4</pre>
        </td>

        <td>
          <pre style="color: #f5deb3" class="src"><span class="type">id</span> <span class="variable-name">obj</span> = [[<span class="type">NSObject</span> alloc] init];

<span class="type">void</span> *<span class="variable-name">p</span> = obj;
[(<span class="type">id</span>)<span class="type">p</span> <span class="variable-name">retain</span>];</pre>
        </td>
      </tr>

      <tr></tr>
    </tbody></table>
</div>

<p>可以用一个实际的例子验证，对象所有权是否被持有。</p>

<div class="codebox">
  <table width="100%"><tbody>
      <tr>
        <td class="line_numbers">
          <pre>1
2
3
4
5
6
7
8</pre>
        </td>

        <td>
          <pre style="color: #f5deb3" class="src"><span class="type">void</span> *<span class="variable-name">p</span> = 0;

{
    <span class="type">id</span> <span class="variable-name">obj</span> = [[<span class="type">NSObject</span> alloc] init];
    p = (__bridge_retained <span class="type">void</span> *)obj;
}

NSLog(@<span class="string">&#34;class=%@&#34;</span>, [(__bridge <span class="type">id</span>)<span class="type">p</span> <span class="variable-name">class</span>]);</pre>
        </td>
      </tr>

      <tr></tr>
    </tbody></table>
</div>

<p>出了大括号的范围后，p 仍然指向一个有效的实体。说明他拥有该对象的所有权，该对象没有因为出其定义范围而被销毁。</p>

<h4><a id="sec4" name="sec4"></a>__bridge_transfer</h4>

<p class="first">相反，当想把本来拥有对象所有权的变量，在类型转换后，让其释放原先所有权的时候，需要使用 __bridge_transfer 关键字。文字有点绕口，我们还是来看一段代码吧。</p>

<p>如果ARC无效的时候，我们可能需要写下面的代码。</p>

<div class="codebox">
  <table width="100%"><tbody>
      <tr>
        <td class="line_numbers">
          <pre>1
2
3
4</pre>
        </td>

        <td>
          <pre style="color: #f5deb3" class="src"><span class="comment-delimiter">// </span><span class="comment">p 变量原先持有对象的所有权
</span><span class="type">id</span> <span class="variable-name">obj</span> = (<span class="type">id</span>)p;
[obj retain];
[(<span class="type">id</span>)<span class="type">p</span> <span class="variable-name">release</span>];</pre>
        </td>
      </tr>

      <tr></tr>
    </tbody></table>
</div>

<p>那么ARC有效后，我们可以用下面的代码来替换：</p>

<div class="codebox">
  <table width="100%"><tbody>
      <tr>
        <td class="line_numbers">
          <pre>1
2</pre>
        </td>

        <td>
          <pre style="color: #f5deb3" class="src"><span class="comment-delimiter">// </span><span class="comment">p 变量原先持有对象的所有权
</span><span class="type">id</span> <span class="variable-name">obj</span> = (__bridge_transfer <span class="type">id</span>)p;</pre>
        </td>
      </tr>

      <tr></tr>
    </tbody></table>
</div>

<p>可以看出来，__bridge_retained 是编译器替我们做了 retain 操作，而 __bridge_transfer 是替我们做了 release<sup><a class="footref" href="#fn.1" name="fnr.1">1</a></sup>。</p>

<h3><a id="sec5" name="sec5"></a>Toll-Free bridged</h3>

<p class="first">在iOS世界，主要有两种对象：Objective-C 对象和 Core Foundation 对象0。Core Foundation 对象主要是有C语言实现的 Core Foundation Framework 的对象，其中也有对象引用计数的概念，只是不是 Cocoa Framework::Foundation Framework 的 retain/release，而是自身的 CFRetain/CFRelease 接口。</p>

<p>这两种对象间可以互相转换和操作，不使用ARC的时候，单纯的用C原因的类型转换，不需要消耗CPU的资源，所以叫做 Toll-Free bridged。比如 NSArray和CFArrayRef, NSString和CFStringRef，他们虽然属于不同的 Framework，但是具有相同的对象结构，所以可以用标准C的类型转换。</p>

<p>比如不使用ARC时，我们用下面的代码：</p>

<div class="codebox">
  <table width="100%"><tbody>
      <tr>
        <td class="line_numbers">
          <pre>1
2</pre>
        </td>

        <td>
          <pre style="color: #f5deb3" class="src"><span class="type">NSString</span> *<span class="variable-name">string</span> = [<span class="type">NSString</span> stringWithFormat:...];
<span class="type">CFStringRef</span> <span class="variable-name">cfString</span> = (<span class="type">CFStringRef</span>)string;</pre>
        </td>
      </tr>

      <tr></tr>
    </tbody></table>
</div>

<p>同样，Core Foundation类型向Objective-C类型转换时，也是简单地用标准C的类型转换即可。</p>

<p>但是在ARC有效的情况下，将出现类似下面的编译错误：</p>

<pre class="example">    Cast of Objective-C pointer type ‘NSString *’ to C pointer type ‘CFStringRef’ (aka ‘const struct __CFString *’) requires a bridged cast
    Use __bridge to convert directly (no change in ownership)
    Use __bridge_retained to make an ARC object available as a +1 ‘CFStringRef’ (aka ‘const struct __CFString *’)</pre>

<p>错误中已经提示了我们需要怎样做：用 __bridge 或者 __bridge_retained 来转型，其差别就是变更对象的所有权。</p>

<p>正因为Objective-C是ARC管理的对象，而Core Foundation不是ARC管理的对象，所以才要特意这样转换，这与id类型向void*转换是一个概念。也就是说，当这两种类型（有ARC管理，没有ARC管理）在转换时，需要告诉编译器怎样处理对象的所有权。</p>

<p>上面的例子，使用 __bridge/__bridge_retained 后的代码如下：</p>
<dl><dt><strong>__bridge</strong></dt><dd></dd></dl>

<div class="codebox">
  <table width="100%"><tbody>
      <tr>
        <td class="line_numbers">
          <pre>1
2</pre>
        </td>

        <td>
          <pre style="color: #f5deb3" class="src"><span class="type">NSString</span> *<span class="variable-name">string</span> = [<span class="type">NSString</span> stringWithFormat:...];
<span class="type">CFStringRef</span> <span class="variable-name">cfString</span> = (__bridge CFStringRef)string;</pre>
        </td>
      </tr>

      <tr></tr>
    </tbody></table>
</div>

<p>只是单纯地执行了类型转换，没有进行所有权的转移，也就是说，当string对象被释放的时候，cfString也不能被使用了。</p>
<dl><dt><strong>__bridge_retained</strong></dt><dd></dd></dl>

<div class="codebox">
  <table width="100%"><tbody>
      <tr>
        <td class="line_numbers">
          <pre>1
2
3
4</pre>
        </td>

        <td>
          <pre style="color: #f5deb3" class="src"><span class="type">NSString</span> *<span class="variable-name">string</span> = [<span class="type">NSString</span> stringWithFormat:...];
<span class="type">CFStringRef</span> <span class="variable-name">cfString</span> = (__bridge_retained CFStringRef)string;
...
CFRelease(cfString); <span class="comment-delimiter">// </span><span class="comment">由于Core Foundation的对象不属于ARC的管理范畴，所以需要自己release
</span></pre>
        </td>
      </tr>

      <tr></tr>
    </tbody></table>
</div>

<p>使用 __bridge_retained 可以通过转换目标处（cfString）的 retain 处理，来使所有权转移。即使 string 变量被释放，cfString 还是可以使用具体的对象。只是有一点，由于Core Foundation的对象不属于ARC的管理范畴，所以需要自己release。</p>

<p>实际上，Core Foundation 内部，为了实现Core Foundation对象类型与Objective-C对象类型的相互转换，提供了下面的函数。</p>

<div class="codebox">
  <table width="100%"><tbody>
      <tr>
        <td class="line_numbers">
          <pre>1
2
3
4
5
6
7</pre>
        </td>

        <td>
          <pre style="color: #f5deb3" class="src"><span class="type">CFTypeRef</span>  <span class="function-name">CFBridgingRetain</span>(<span class="type">id</span>  <span class="variable-name">X</span>)  {
    <span class="keyword">return</span>  (__bridge_retained  CFTypeRef)X;
}

<span class="type">id</span>  <span class="function-name">CFBridgingRelease</span>(<span class="type">CFTypeRef</span>  <span class="variable-name">X</span>)  {
    <span class="keyword">return</span>  (__bridge_transfer  <span class="type">id</span>)X;
}</pre>
        </td>
      </tr>

      <tr></tr>
    </tbody></table>
</div>

<p>所以，可以用 CFBridgingRetain 替代 __bridge_retained 关键字：</p>

<div class="codebox">
  <table width="100%"><tbody>
      <tr>
        <td class="line_numbers">
          <pre>1
2
3
4</pre>
        </td>

        <td>
          <pre style="color: #f5deb3" class="src"><span class="type">NSString</span> *<span class="variable-name">string</span> = [<span class="type">NSString</span> stringWithFormat:...];
<span class="type">CFStringRef</span> <span class="variable-name">cfString</span> = CFBridgingRetain(string);
...
CFRelease(cfString); <span class="comment-delimiter">// </span><span class="comment">由于Core Foundation不在ARC管理范围内，所以需要主动release。
</span></pre>
        </td>
      </tr>

      <tr></tr>
    </tbody></table>
</div>
<dl><dt><strong>__bridge_transfer</strong></dt><dd></dd></dl>

<p>所有权被转移的同时，被转换变量将失去对象的所有权。当Core Foundation对象类型向Objective-C对象类型转换的时候，会经常用到 __bridge_transfer 关键字。</p>

<div class="codebox">
  <table width="100%"><tbody>
      <tr>
        <td class="line_numbers">
          <pre>1
2
3
4</pre>
        </td>

        <td>
          <pre style="color: #f5deb3" class="src"><span class="type">CFStringRef</span> <span class="variable-name">cfString</span> = CFStringCreate...();
<span class="type">NSString</span> *<span class="variable-name">string</span> = (__bridge_transfer NSString *)cfString;

<span class="comment-delimiter">// </span><span class="comment">CFRelease(cfString); 因为已经用 __bridge_transfer 转移了对象的所有权，所以不需要调用 release
</span></pre>
        </td>
      </tr>

      <tr></tr>
    </tbody></table>
</div>

<p>同样，我们可以使用 CFBridgingRelease() 来代替 __bridge_transfer 关键字。</p>

<div class="codebox">
  <table width="100%"><tbody>
      <tr>
        <td class="line_numbers">
          <pre>1
2</pre>
        </td>

        <td>
          <pre style="color: #f5deb3" class="src"><span class="type">CFStringRef</span> <span class="variable-name">cfString</span> = CFStringCreate...();
<span class="type">NSString</span> *<span class="variable-name">string</span> = CFBridgingRelease(cfString);</pre>
        </td>
      </tr>

      <tr></tr>
    </tbody></table>
</div>

<h3><a id="sec6" name="sec6"></a>总结</h3>

<p class="first">由上面的学习我们了解到 ARC 中类型转换的用法，那么我们实际使用中按照怎样的原则或者方法来区分使用呢，下面我总结了几点关键要素。</p>

<ul>
  <li>明确被转换类型是否是 ARC 管理的对象 
    <ul>
      <li>Core Foundation 对象类型不在 ARC 管理范畴内 </li>

      <li>Cocoa Framework::Foundation 对象类型（即一般使用到的Objectie-C对象类型）在 ARC 的管理范畴内 </li>
    </ul>
  </li>

  <li>如果不在 ARC 管理范畴内的对象，那么要清楚 release 的责任应该是谁 </li>

  <li>各种对象的生命周期是怎样的 </li>
</ul>

<hr />

<p class="footnote"><a class="footnum" href="#fnr.1" name="fn.1">1.</a> 声明 id obj 的时候，其实是缺省的申明了一个 __strong 修饰的变量，所以编译器自动地加入了 retain 的处理，所以说 __bridge_transfer 关键字只为我们做了 release 处理。</p>]]></description>
			<content:encoded><![CDATA[<div class="contents">
<dt><a href="#sec1">引子</a> </dt>
<dt><a href="#sec2">__bridge</a> </dt>
<dd>
<dl>
<dt><a href="#sec3">__bridge_retained</a> </dt>
<dt><a href="#sec4">__bridge_transfer</a> </dt>
</dl>
</dd>
<dt><a href="#sec5">Toll-Free bridged</a> </dt>
<dt><a href="#sec6">总结</a> </dt>
</div>
<p style="text-align: center"><strong>iPhone开发之深入浅出 (6) — ARC之对象转型</strong> </p>
<p>自 Xcode4.2 开始导入ARC机制后，为了支持对象间的转型，Apple又增加了许多转型用的关键字。这一讲我们就来了解其用法，以及产生的理由。</p>
<h3><a id="sec1" name="sec1"></a>引子</h3>
<p class="first">我们先来看一下ARC无效的时候，我们写id类型转void*类型的写法：</p>
<div class="codebox">
<table width="100%">
<tbody>
<tr>
<td class="line_numbers">
<pre>1
2</pre>
</td>
<td>
<pre style="color: #f5deb3" class="src"><span class="type">id</span> <span class="variable-name">obj</span> = [[<span class="type">NSObject</span> alloc] init];
<span class="type">void</span> *<span class="variable-name">p</span> = obj;</pre>
</td>
</tr>
<tr></tr>
</tbody>
</table>
</div>
<p>反过来，当把void*对象变回id类型时，只是简单地如下来写，</p>
<div class="codebox">
<table width="100%">
<tbody>
<tr>
<td class="line_numbers">
<pre>1
2</pre>
</td>
<td>
<pre style="color: #f5deb3" class="src"><span class="type">id</span> <span class="variable-name">obj</span> = p;
[obj release];</pre>
</td>
</tr>
<tr></tr>
</tbody>
</table>
</div>
<p>但是上面的代码在ARC有效时，就有了下面的错误：</p>
<pre class="example">    error: implicit conversion of an Objective-C pointer
        to ’void *’ is disallowed with ARC
        void *p = obj;
                  ^

    error: implicit conversion of a non-Objective-C pointer
        type ’void *’ to ’id’ is disallowed with ARC
        id o = p;
                ^</pre>
<h3><a id="sec2" name="sec2"></a>__bridge</h3>
<p class="first">为了解决这一问题，我们使用 <strong>__bridge</strong> 关键字来实现id类型与void*类型的相互转换。看下面的例子。</p>
<div class="codebox">
<table width="100%">
<tbody>
<tr>
<td class="line_numbers">
<pre>1
2
3
4
5</pre>
</td>
<td>
<pre style="color: #f5deb3" class="src"><span class="type">id</span> <span class="variable-name">obj</span> = [[<span class="type">NSObject</span> alloc] init];

<span class="type">void</span> *<span class="variable-name">p</span> = (__bridge <span class="type">void</span> *)obj;

<span class="type">id</span> <span class="variable-name">o</span> = (__bridge <span class="type">id</span>)p;</pre>
</td>
</tr>
<tr></tr>
</tbody>
</table>
</div>
<p>将Objective-C的对象类型用 __bridge 转换为 void* 类型和使用 __unsafe_unretained 关键字修饰的变量是一样的。被代入对象的所有者需要明确对象生命周期的管理，不要出现异常访问的问题。</p>
<p>除过 __bridge 以外，还有两个 __bridge 相关的类型转换关键字：</p>
<ul>
<li>__bridge_retained </li>
<li>__bridge_transfer </li>
</ul>
<p>接下来，我们将看看这两个关键字的区别。</p>
<h4><a id="sec3" name="sec3"></a>__bridge_retained</h4>
<p class="first">先来看使用 __bridge_retained 关键字的例子程序：</p>
<div class="codebox">
<table width="100%">
<tbody>
<tr>
<td class="line_numbers">
<pre>1
2
3</pre>
</td>
<td>
<pre style="color: #f5deb3" class="src"><span class="type">id</span> <span class="variable-name">obj</span> = [[<span class="type">NSObject</span> alloc] init];

<span class="type">void</span> *<span class="variable-name">p</span> = (__bridge_retained <span class="type">void</span> *)obj;</pre>
</td>
</tr>
<tr></tr>
</tbody>
</table>
</div>
<p>从名字上我们应该能理解其意义：类型被转换时，其对象的所有权也将被变换后变量所持有。如果不是ARC代码，类似下面的实现：</p>
<div class="codebox">
<table width="100%">
<tbody>
<tr>
<td class="line_numbers">
<pre>1
2
3
4</pre>
</td>
<td>
<pre style="color: #f5deb3" class="src"><span class="type">id</span> <span class="variable-name">obj</span> = [[<span class="type">NSObject</span> alloc] init];

<span class="type">void</span> *<span class="variable-name">p</span> = obj;
[(<span class="type">id</span>)<span class="type">p</span> <span class="variable-name">retain</span>];</pre>
</td>
</tr>
<tr></tr>
</tbody>
</table>
</div>
<p>可以用一个实际的例子验证，对象所有权是否被持有。</p>
<div class="codebox">
<table width="100%">
<tbody>
<tr>
<td class="line_numbers">
<pre>1
2
3
4
5
6
7
8</pre>
</td>
<td>
<pre style="color: #f5deb3" class="src"><span class="type">void</span> *<span class="variable-name">p</span> = 0;

{
    <span class="type">id</span> <span class="variable-name">obj</span> = [[<span class="type">NSObject</span> alloc] init];
    p = (__bridge_retained <span class="type">void</span> *)obj;
}

NSLog(@<span class="string">&quot;class=%@&quot;</span>, [(__bridge <span class="type">id</span>)<span class="type">p</span> <span class="variable-name">class</span>]);</pre>
</td>
</tr>
<tr></tr>
</tbody>
</table>
</div>
<p>出了大括号的范围后，p 仍然指向一个有效的实体。说明他拥有该对象的所有权，该对象没有因为出其定义范围而被销毁。</p>
<h4><a id="sec4" name="sec4"></a>__bridge_transfer</h4>
<p class="first">相反，当想把本来拥有对象所有权的变量，在类型转换后，让其释放原先所有权的时候，需要使用 __bridge_transfer 关键字。文字有点绕口，我们还是来看一段代码吧。</p>
<p>如果ARC无效的时候，我们可能需要写下面的代码。</p>
<div class="codebox">
<table width="100%">
<tbody>
<tr>
<td class="line_numbers">
<pre>1
2
3
4</pre>
</td>
<td>
<pre style="color: #f5deb3" class="src"><span class="comment-delimiter">// </span><span class="comment">p 变量原先持有对象的所有权
</span><span class="type">id</span> <span class="variable-name">obj</span> = (<span class="type">id</span>)p;
[obj retain];
[(<span class="type">id</span>)<span class="type">p</span> <span class="variable-name">release</span>];</pre>
</td>
</tr>
<tr></tr>
</tbody>
</table>
</div>
<p>那么ARC有效后，我们可以用下面的代码来替换：</p>
<div class="codebox">
<table width="100%">
<tbody>
<tr>
<td class="line_numbers">
<pre>1
2</pre>
</td>
<td>
<pre style="color: #f5deb3" class="src"><span class="comment-delimiter">// </span><span class="comment">p 变量原先持有对象的所有权
</span><span class="type">id</span> <span class="variable-name">obj</span> = (__bridge_transfer <span class="type">id</span>)p;</pre>
</td>
</tr>
<tr></tr>
</tbody>
</table>
</div>
<p>可以看出来，__bridge_retained 是编译器替我们做了 retain 操作，而 __bridge_transfer 是替我们做了 release<sup><a class="footref" href="#fn.1" name="fnr.1">1</a></sup>。</p>
<h3><a id="sec5" name="sec5"></a>Toll-Free bridged</h3>
<p class="first">在iOS世界，主要有两种对象：Objective-C 对象和 Core Foundation 对象0。Core Foundation 对象主要是有C语言实现的 Core Foundation Framework 的对象，其中也有对象引用计数的概念，只是不是 Cocoa Framework::Foundation Framework 的 retain/release，而是自身的 CFRetain/CFRelease 接口。</p>
<p>这两种对象间可以互相转换和操作，不使用ARC的时候，单纯的用C原因的类型转换，不需要消耗CPU的资源，所以叫做 Toll-Free bridged。比如 NSArray和CFArrayRef, NSString和CFStringRef，他们虽然属于不同的 Framework，但是具有相同的对象结构，所以可以用标准C的类型转换。</p>
<p>比如不使用ARC时，我们用下面的代码：</p>
<div class="codebox">
<table width="100%">
<tbody>
<tr>
<td class="line_numbers">
<pre>1
2</pre>
</td>
<td>
<pre style="color: #f5deb3" class="src"><span class="type">NSString</span> *<span class="variable-name">string</span> = [<span class="type">NSString</span> stringWithFormat:...];
<span class="type">CFStringRef</span> <span class="variable-name">cfString</span> = (<span class="type">CFStringRef</span>)string;</pre>
</td>
</tr>
<tr></tr>
</tbody>
</table>
</div>
<p>同样，Core Foundation类型向Objective-C类型转换时，也是简单地用标准C的类型转换即可。</p>
<p>但是在ARC有效的情况下，将出现类似下面的编译错误：</p>
<pre class="example">    Cast of Objective-C pointer type ‘NSString *’ to C pointer type ‘CFStringRef’ (aka ‘const struct __CFString *’) requires a bridged cast
    Use __bridge to convert directly (no change in ownership)
    Use __bridge_retained to make an ARC object available as a +1 ‘CFStringRef’ (aka ‘const struct __CFString *’)</pre>
<p>错误中已经提示了我们需要怎样做：用 __bridge 或者 __bridge_retained 来转型，其差别就是变更对象的所有权。</p>
<p>正因为Objective-C是ARC管理的对象，而Core Foundation不是ARC管理的对象，所以才要特意这样转换，这与id类型向void*转换是一个概念。也就是说，当这两种类型（有ARC管理，没有ARC管理）在转换时，需要告诉编译器怎样处理对象的所有权。</p>
<p>上面的例子，使用 __bridge/__bridge_retained 后的代码如下：</p>
<dl>
<dt><strong>__bridge</strong></dt>
<dd></dd>
</dl>
<div class="codebox">
<table width="100%">
<tbody>
<tr>
<td class="line_numbers">
<pre>1
2</pre>
</td>
<td>
<pre style="color: #f5deb3" class="src"><span class="type">NSString</span> *<span class="variable-name">string</span> = [<span class="type">NSString</span> stringWithFormat:...];
<span class="type">CFStringRef</span> <span class="variable-name">cfString</span> = (__bridge CFStringRef)string;</pre>
</td>
</tr>
<tr></tr>
</tbody>
</table>
</div>
<p>只是单纯地执行了类型转换，没有进行所有权的转移，也就是说，当string对象被释放的时候，cfString也不能被使用了。</p>
<dl>
<dt><strong>__bridge_retained</strong></dt>
<dd></dd>
</dl>
<div class="codebox">
<table width="100%">
<tbody>
<tr>
<td class="line_numbers">
<pre>1
2
3
4</pre>
</td>
<td>
<pre style="color: #f5deb3" class="src"><span class="type">NSString</span> *<span class="variable-name">string</span> = [<span class="type">NSString</span> stringWithFormat:...];
<span class="type">CFStringRef</span> <span class="variable-name">cfString</span> = (__bridge_retained CFStringRef)string;
...
CFRelease(cfString); <span class="comment-delimiter">// </span><span class="comment">由于Core Foundation的对象不属于ARC的管理范畴，所以需要自己release
</span></pre>
</td>
</tr>
<tr></tr>
</tbody>
</table>
</div>
<p>使用 __bridge_retained 可以通过转换目标处（cfString）的 retain 处理，来使所有权转移。即使 string 变量被释放，cfString 还是可以使用具体的对象。只是有一点，由于Core Foundation的对象不属于ARC的管理范畴，所以需要自己release。</p>
<p>实际上，Core Foundation 内部，为了实现Core Foundation对象类型与Objective-C对象类型的相互转换，提供了下面的函数。</p>
<div class="codebox">
<table width="100%">
<tbody>
<tr>
<td class="line_numbers">
<pre>1
2
3
4
5
6
7</pre>
</td>
<td>
<pre style="color: #f5deb3" class="src"><span class="type">CFTypeRef</span>  <span class="function-name">CFBridgingRetain</span>(<span class="type">id</span>  <span class="variable-name">X</span>)  {
    <span class="keyword">return</span>  (__bridge_retained  CFTypeRef)X;
}

<span class="type">id</span>  <span class="function-name">CFBridgingRelease</span>(<span class="type">CFTypeRef</span>  <span class="variable-name">X</span>)  {
    <span class="keyword">return</span>  (__bridge_transfer  <span class="type">id</span>)X;
}</pre>
</td>
</tr>
<tr></tr>
</tbody>
</table>
</div>
<p>所以，可以用 CFBridgingRetain 替代 __bridge_retained 关键字：</p>
<div class="codebox">
<table width="100%">
<tbody>
<tr>
<td class="line_numbers">
<pre>1
2
3
4</pre>
</td>
<td>
<pre style="color: #f5deb3" class="src"><span class="type">NSString</span> *<span class="variable-name">string</span> = [<span class="type">NSString</span> stringWithFormat:...];
<span class="type">CFStringRef</span> <span class="variable-name">cfString</span> = CFBridgingRetain(string);
...
CFRelease(cfString); <span class="comment-delimiter">// </span><span class="comment">由于Core Foundation不在ARC管理范围内，所以需要主动release。
</span></pre>
</td>
</tr>
<tr></tr>
</tbody>
</table>
</div>
<dl>
<dt><strong>__bridge_transfer</strong></dt>
<dd></dd>
</dl>
<p>所有权被转移的同时，被转换变量将失去对象的所有权。当Core Foundation对象类型向Objective-C对象类型转换的时候，会经常用到 __bridge_transfer 关键字。</p>
<div class="codebox">
<table width="100%">
<tbody>
<tr>
<td class="line_numbers">
<pre>1
2
3
4</pre>
</td>
<td>
<pre style="color: #f5deb3" class="src"><span class="type">CFStringRef</span> <span class="variable-name">cfString</span> = CFStringCreate...();
<span class="type">NSString</span> *<span class="variable-name">string</span> = (__bridge_transfer NSString *)cfString;

<span class="comment-delimiter">// </span><span class="comment">CFRelease(cfString); 因为已经用 __bridge_transfer 转移了对象的所有权，所以不需要调用 release
</span></pre>
</td>
</tr>
<tr></tr>
</tbody>
</table>
</div>
<p>同样，我们可以使用 CFBridgingRelease() 来代替 __bridge_transfer 关键字。</p>
<div class="codebox">
<table width="100%">
<tbody>
<tr>
<td class="line_numbers">
<pre>1
2</pre>
</td>
<td>
<pre style="color: #f5deb3" class="src"><span class="type">CFStringRef</span> <span class="variable-name">cfString</span> = CFStringCreate...();
<span class="type">NSString</span> *<span class="variable-name">string</span> = CFBridgingRelease(cfString);</pre>
</td>
</tr>
<tr></tr>
</tbody>
</table>
</div>
<h3><a id="sec6" name="sec6"></a>总结</h3>
<p class="first">由上面的学习我们了解到 ARC 中类型转换的用法，那么我们实际使用中按照怎样的原则或者方法来区分使用呢，下面我总结了几点关键要素。</p>
<ul>
<li>明确被转换类型是否是 ARC 管理的对象
<ul>
<li>Core Foundation 对象类型不在 ARC 管理范畴内 </li>
<li>Cocoa Framework::Foundation 对象类型（即一般使用到的Objectie-C对象类型）在 ARC 的管理范畴内 </li>
</ul>
</li>
<li>如果不在 ARC 管理范畴内的对象，那么要清楚 release 的责任应该是谁 </li>
<li>各种对象的生命周期是怎样的 </li>
</ul>
<hr />
<p class="footnote"><a class="footnum" href="#fnr.1" name="fn.1">1.</a> 声明 id obj 的时候，其实是缺省的申明了一个 __strong 修饰的变量，所以编译器自动地加入了 retain 的处理，所以说 __bridge_transfer 关键字只为我们做了 release 处理。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.yifeiyang.net/development-of-the-iphone-simply-6/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>iPhone开发之深入浅出 (5) &#8212; ARC之Outlet与弱引用</title>
		<link>http://www.yifeiyang.net/development-of-the-iphone-simply-5/</link>
		<comments>http://www.yifeiyang.net/development-of-the-iphone-simply-5/#comments</comments>
		<pubDate>Thu, 08 Mar 2012 00:04:04 +0000</pubDate>
		<dc:creator>yang</dc:creator>
				<category><![CDATA[ARC]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[深入浅出]]></category>
		<category><![CDATA[iOS]]></category>

		<guid isPermaLink="false">http://www.yifeiyang.net/?p=464</guid>
		<description><![CDATA[<div class="contents">
<dt>
<a href="#sec1">使用weak property声明Outlet</a>
</dt>
<dd>
<dl>
<dt>
<a href="#sec2">简化viewDidUnload</a>
</dt>
<dt>
<a href="#sec3">什么时候要用strong property</a>
</dt>
</dl>
</dd>
</div>



<p style="text-align: center;">
<strong>iPhone开发之深入浅出 (5) &#8212; ARC之Outlet与弱引用</strong>
</p>


<h3><a name="sec1" id="sec1"></a>使用weak property声明Outlet</h3>

<p class="first">当我们使用 Interface Builder 生成Outlet对象的时候，一般都是作为 subview 来使用的。比如 UIViewController 的view。所以说Outlet的持有者就是superview对象，即有“父子”关系。由上一回 <a href="http://www.yifeiyang.net/development-of-the-iphone-simply-4/">iPhone开发之深入浅出 (4) — ARC之循环参照</a> 我们知道，当对象间有“父子”关系时，需要使用弱参照，以避免“循环参照”。</p>

<p>ViewController 本身是不会作为Outlet的所有者的，所以使用weak property声明。</p>


<div class="imagebox">
<p><a href="http://www.yifeiyang.net/images/iphone/ARC/arc_outlet_weak_property.png">
<img src="http://www.yifeiyang.net/images/iphone/ARC/arc_outlet_weak_property.png" alt="arc_outlet_weak_property"/></a>
</p></div>


<h4><a name="sec2" id="sec2"></a>简化viewDidUnload</h4>

<p class="first">Outlet都使用weak property声明的时候，还有一个好处，就是简化viewDidUnload的处理。</p>

<p>iOS在系统内存不足的时候，UIViewController会将没有表示的所有view做unload处理，即调用viewDidUnload接口。</p>

<p>所以，如果是强参照的情况下，需要释放所有权，</p>

<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
</pre></td><td>
<pre class="src" style="color:#f5deb3;">@property (nonatomic, strong) IBOutlet <span class="type">UILabel</span> *<span class="variable-name">label</span>;
</pre></td><tr></table></div>


<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
</pre></td><td>
<pre class="src" style="color:#f5deb3;">(<span class="type">void</span>)viewDidUnload {
    <span class="keyword">self</span>.label = <span class="constant">nil</span>; <span class="comment-delimiter">// </span><span class="comment">&#21462;&#28040;&#24378;&#21442;&#29031;&#65292;&#37322;&#25918;&#25152;&#26377;&#26435;
</span>    [<span class="keyword">super</span> viewDidUnload];
}
</pre></td><tr></table></div>


<p>如果没有 self.label = nil 的处理，那么 UIViewController 将不会释放 label 的所有权；结果，系统是调用了unload，但是subview对象始终留在内存中。随着界面上控件的增多，内存泄露会越来越大。</p>


<p>如果使用的是weak property声明的话，会是怎样的呢？</p>

<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
</pre></td><td>
<pre class="src" style="color:#f5deb3;">@property (nonatomic, weak) IBOutlet <span class="type">UILabel</span> *<span class="variable-name">label</span>;
</pre></td><tr></table></div>


<p>这时，系统在unload时，由于label没有被强参照，更加ARC的规则，这时，label的对象即被释放。并在释放的同时，变量自动指向nil。</p>


<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
</pre></td><td>
<pre class="src" style="color:#f5deb3;">- (<span class="type">void</span>)<span class="function-name">viewDidUnload</span> {
    <span class="comment-delimiter">// </span><span class="comment">&#36825;&#37324;&#20160;&#20040;&#20063;&#19981;&#29992;&#31649;
</span>    [<span class="keyword">super</span> viewDidUnload];
}
</pre></td><tr></table></div>


<blockquote>
<p class="quoted">其实，如果我们的viewDidUnload只是用来释放Outlet用的话，那么该函数也可以不被重载的。</p>
</blockquote>


<h4><a name="sec3" id="sec3"></a>什么时候要用strong property</h4>

<p class="first">由上我们也可以看到，并不是所有的Outlet都用弱参照来声明都是正确的；当使用Interface Builder生成的第一层的view或
者windows被作为Outlet来使用的话，那么不是不能声明为弱参照property的。（比如，Storyboard的各个scene）</p>

<blockquote>
<p class="quoted">理由很简单，没有被任何人强参照的对象，生成之后就会立刻被释放。</p>
</blockquote>

<p>综上，当我们使用Outlet的时候，注意不同的情况来使用strong或者是weak。</p>]]></description>
			<content:encoded><![CDATA[<div class="contents">
<dt>
<a href="#sec1">使用weak property声明Outlet</a>
</dt>
<dd>
<dl>
<dt>
<a href="#sec2">简化viewDidUnload</a>
</dt>
<dt>
<a href="#sec3">什么时候要用strong property</a>
</dt>
</dl>
</dd>
</div>
<p style="text-align: center;">
<strong>iPhone开发之深入浅出 (5) &mdash; ARC之Outlet与弱引用</strong>
</p>
<h3><a name="sec1" id="sec1"></a>使用weak property声明Outlet</h3>
<p class="first">当我们使用 Interface Builder 生成Outlet对象的时候，一般都是作为 subview 来使用的。比如 UIViewController 的view。所以说Outlet的持有者就是superview对象，即有“父子”关系。由上一回 <a href="http://www.yifeiyang.net/development-of-the-iphone-simply-4/">iPhone开发之深入浅出 (4) — ARC之循环参照</a> 我们知道，当对象间有“父子”关系时，需要使用弱参照，以避免“循环参照”。</p>
<p>ViewController 本身是不会作为Outlet的所有者的，所以使用weak property声明。</p>
<div class="imagebox">
<p><a href="http://www.yifeiyang.net/images/iphone/ARC/arc_outlet_weak_property.png" rel="lightbox[464]"><br />
<img src="http://www.yifeiyang.net/images/iphone/ARC/arc_outlet_weak_property.png" alt="arc_outlet_weak_property"/></a>
</p>
</div>
<h4><a name="sec2" id="sec2"></a>简化viewDidUnload</h4>
<p class="first">Outlet都使用weak property声明的时候，还有一个好处，就是简化viewDidUnload的处理。</p>
<p>iOS在系统内存不足的时候，UIViewController会将没有表示的所有view做unload处理，即调用viewDidUnload接口。</p>
<p>所以，如果是强参照的情况下，需要释放所有权，</p>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;">@property (nonatomic, strong) IBOutlet <span class="type">UILabel</span> *<span class="variable-name">label</span>;
</pre>
</td>
<tr></table>
</div>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;">(<span class="type">void</span>)viewDidUnload {
    <span class="keyword">self</span>.label = <span class="constant">nil</span>; <span class="comment-delimiter">// </span><span class="comment">&#21462;&#28040;&#24378;&#21442;&#29031;&#65292;&#37322;&#25918;&#25152;&#26377;&#26435;
</span>    [<span class="keyword">super</span> viewDidUnload];
}
</pre>
</td>
<tr></table>
</div>
<p>如果没有 self.label = nil 的处理，那么 UIViewController 将不会释放 label 的所有权；结果，系统是调用了unload，但是subview对象始终留在内存中。随着界面上控件的增多，内存泄露会越来越大。</p>
<p>如果使用的是weak property声明的话，会是怎样的呢？</p>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;">@property (nonatomic, weak) IBOutlet <span class="type">UILabel</span> *<span class="variable-name">label</span>;
</pre>
</td>
<tr></table>
</div>
<p>这时，系统在unload时，由于label没有被强参照，更加ARC的规则，这时，label的对象即被释放。并在释放的同时，变量自动指向nil。</p>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;">- (<span class="type">void</span>)<span class="function-name">viewDidUnload</span> {
    <span class="comment-delimiter">// </span><span class="comment">&#36825;&#37324;&#20160;&#20040;&#20063;&#19981;&#29992;&#31649;
</span>    [<span class="keyword">super</span> viewDidUnload];
}
</pre>
</td>
<tr></table>
</div>
<blockquote>
<p class="quoted">其实，如果我们的viewDidUnload只是用来释放Outlet用的话，那么该函数也可以不被重载的。</p>
</blockquote>
<h4><a name="sec3" id="sec3"></a>什么时候要用strong property</h4>
<p class="first">由上我们也可以看到，并不是所有的Outlet都用弱参照来声明都是正确的；当使用Interface Builder生成的第一层的view或<br />
者windows被作为Outlet来使用的话，那么不是不能声明为弱参照property的。（比如，Storyboard的各个scene）</p>
<blockquote>
<p class="quoted">理由很简单，没有被任何人强参照的对象，生成之后就会立刻被释放。</p>
</blockquote>
<p>综上，当我们使用Outlet的时候，注意不同的情况来使用strong或者是weak。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.yifeiyang.net/development-of-the-iphone-simply-5/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>iPhone开发之深入浅出 (4) &#8212; ARC之循环参照</title>
		<link>http://www.yifeiyang.net/development-of-the-iphone-simply-4/</link>
		<comments>http://www.yifeiyang.net/development-of-the-iphone-simply-4/#comments</comments>
		<pubDate>Thu, 01 Mar 2012 00:06:49 +0000</pubDate>
		<dc:creator>yang</dc:creator>
				<category><![CDATA[ARC]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[深入浅出]]></category>
		<category><![CDATA[iOS]]></category>

		<guid isPermaLink="false">http://www.yifeiyang.net/?p=455</guid>
		<description><![CDATA[<div class="contents">
<dt>
<a href="#sec1">概念</a>
</dt>
<dt>
<a href="#sec2">解决方式</a>
</dt>
<dd>
<dl>
<dt>
<a href="#sec3">Delegate模式</a>
</dt>
<dt>
<a href="#sec4">Blocks</a>
</dt>
</dl>
</dd>
</div>



<p style="text-align: center;">
<strong>iPhone开发之深入浅出 (4) &#8212; ARC之循环参照</strong>
</p>

<h3><a name="sec1" id="sec1"></a>概念</h3>

<p class="first">当我们使用强参照（Strong reference）时，往往需要留意 <strong>循环参照</strong> 的问题。循环参照指的是两个对象被互相强参照，以至于任一对象都不能释放。</p>

<p>一般情况下，当对象之间有“父子关系”时，强参照的情况发生的比较多。比如通讯薄对象AddrBook和每个通讯录Entry的关系如下。</p>

<div class="imagebox">
<p><a href="http://www.yifeiyang.net/images/iphone/ARC/arc_reference_cycle_1.png">
<img src="http://www.yifeiyang.net/images/iphone/ARC/arc_reference_cycle_1.png" alt="arc_reference_cycle"/></a>
</p></div>


<p>这种情况下，由于Entry对象被AddrBook强参照，所以不能释放。另一方面，如果Entry被释放了，AddrBook对象的强参照也就没有了，其对象也应被释放。</p>


<h3><a name="sec2" id="sec2"></a>解决方式</h3>

<p class="first">像上面的例子，当多个对象间有“父子关系”时，需要在一侧用“弱参照”来解决循环参照问题。一般情况下，“父亲”作为“孩子”的拥有者，对“孩子”是强参照，而“孩子”对父亲是弱参照。</p>

<div class="imagebox">
<p><a href="http://www.yifeiyang.net/images/iphone/ARC/arc_reference_cycle_2.png">
<img src="http://www.yifeiyang.net/images/iphone/ARC/arc_reference_cycle_2.png" alt="arc_reference_cycle"/></a>
</p></div>

<p>如图所示，当强参照AddrBook对象的变量被释放的时候，AddrBook对象将被自动释放，同时将失去Entry成员对象的强参照。另外，当AddrBook对象被释放的时候，Entry对象中的AddrBook变量也将由Zeroing机制，自动带入nil。我们不需要担心释放对象的再访问问题。</p>

<p>下面，我们将看看有几种情况下，需要注意循环参照问题。</p>

<h4><a name="sec3" id="sec3"></a>Delegate模式</h4>

<p class="first">iOS程序中经常用到delegate模式，比如ViewController中，用ModalView打开/关闭DetailViewController时，需要delegate的设定。</p>

<div class="imagebox">
<p><a href="http://www.yifeiyang.net/images/iphone/ARC/arc_reference_cycle_3.png">
<img src="http://www.yifeiyang.net/images/iphone/ARC/arc_reference_cycle_3.png" alt="arc_reference_cycle"/></a>
</p></div>

<p>这里，ViewController对象中强参照detailViewController，如果DetailViewController的delegate不是弱参照ViewController话，将引起循环参照。</p>

<p>另外，当类中使用weak @property声明的delegate变量时，如果参照对象被释放，该变量将被自动设为nil，不需要程序代码设置。</p>


<h4><a name="sec4" id="sec4"></a>Blocks</h4>

<p class="first">Blocks是iOS 4开始导入的，可以理解为python或者lisp中的Lambda，C++11也已导入了该概念；类似概念ruby/smalltalk/JSP语言中也有定义。具体讲解见以后的文章，本节我们主要看看在Block中的循环参照问题。</p>

<p>比如，block对象用copy的属性定义时候，</p>

<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
</pre></td><td>
<pre class="src" style="color:#f5deb3;"><span class="keyword">typedef</span> <span class="type">void</span>(^MyBlock)(<span class="type">void</span>);

<span class="keyword">@interface</span> <span class="type">MyObject</span> : <span class="type">NSObject</span>
@property (nonatomic, copy) <span class="type">MyBlock</span> <span class="variable-name">block</span>;
@property (nonatomic, strong) <span class="type">NSString</span> *<span class="variable-name">str</span>;

- (<span class="type">void</span>)<span class="function-name">performBlock</span>;
<span class="keyword">@end</span>

<span class="keyword">@implementation</span> <span class="type">MyObject</span>
<span class="type">@synthesize</span> <span class="type">block</span>, <span class="type">str</span>;

- (<span class="type">void</span>)<span class="function-name">performBlock</span> {
    <span class="keyword">if</span> (<span class="keyword">self</span>.block) {
        <span class="keyword">self</span>.block();
    }
}
<span class="keyword">@end</span>
</pre></td><tr></table></div>



<p>调用端如下：</p>


<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
</pre></td><td>
<pre class="src" style="color:#f5deb3;"><span class="type">MyObject</span> *<span class="variable-name">object</span> = [[<span class="type">MyObject</span> alloc] init];
object.str = @<span class="string">"hoge"</span>;

object.block = ^{
    NSLog(@<span class="string">"block: str=%@"</span>, object.str);
};
[object performBlock];
</pre></td><tr></table></div>



<p>我们看到，Block的构文中参照了object，同样object也强参照block。</p>


<div class="imagebox">
<p><a href="http://www.yifeiyang.net/images/iphone/ARC/arc_reference_cycle_4.png">
<img src="http://www.yifeiyang.net/images/iphone/ARC/arc_reference_cycle_4.png" alt="arc_reference_cycle"/></a>
</p></div>


<p>为了解决该问题，我们可以有下面两种选择。</p>

<h5>使用__block关键字修饰</h5>

<p>使用__block关键字，让对象有读写权限，如果Block内的处理完毕就释放object。</p>

<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
</pre></td><td>
<pre class="src" style="color:#f5deb3;">__block MyObject *object = [[<span class="type">MyObject</span> alloc] init];
object.str = @<span class="string">"hoge"</span>;

object.block = ^{
    NSLog(@<span class="string">"block: str=%@"</span>, object.str);
    object = <span class="constant">nil</span>;
};
[object performBlock];
</pre></td><tr></table></div>


<p>该关键字的意思就是让block取消对object的强参照，以避免循环参照。但是，有一个问题就是，object的释放动作是在Block内部执行，如果Block没有被执行的话，循环参照一直存在。比如上面的代码，如果第8行 [object performBlock]; 没有执行的话，那么一直还是循环参照状态。</p>


<h5>使用__weak关键字修饰</h5>

<p>另一种方案就是让Block的参照变为弱参照。</p>

<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
</pre></td><td>
<pre class="src" style="color:#f5deb3;"><span class="type">MyObject</span> *<span class="variable-name">object</span> = [[<span class="type">MyObject</span> alloc] init];
object.str = @<span class="string">"hoge"</span>;

__weak MyObject *weakObject = object;
object.block = ^{
    NSLog(@<span class="string">"block: str=%@"</span>, weakObject.str);
};
[object performBlock];
</pre></td><tr></table></div>



<p>考虑到异步通信时Blocks的使用情况，weak变量weakObject有可能随时变为nil，所以类似于下面先变为strong变量，并检查是否为nil的处理方式应该更安全。</p>

<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
9
10
11
</pre></td><td>
<pre class="src" style="color:#f5deb3;"><span class="type">MyObject</span> *<span class="variable-name">object</span> = [[<span class="type">MyObject</span> alloc] init];
object.str = @<span class="string">"hoge"</span>;

__weak MyObject *weakObject = object;
object.block = ^{
    <span class="type">MyObject</span> <span class="variable-name">strongObject</span> = weakObject;
    <span class="keyword">if</span> (strongObject) {
        NSLog(@<span class="string">"block: str=%@"</span>, strongObject.str);
    }
};
[object performBlock];
</pre></td><tr></table></div>



<p>总上，当我们使用Blocks时，也需要考虑Block中变量和实例的关系，不要引起不必要的循环参照问题。</p>]]></description>
			<content:encoded><![CDATA[<div class="contents">
<dt>
<a href="#sec1">概念</a>
</dt>
<dt>
<a href="#sec2">解决方式</a>
</dt>
<dd>
<dl>
<dt>
<a href="#sec3">Delegate模式</a>
</dt>
<dt>
<a href="#sec4">Blocks</a>
</dt>
</dl>
</dd>
</div>
<p style="text-align: center;">
<strong>iPhone开发之深入浅出 (4) &mdash; ARC之循环参照</strong>
</p>
<h3><a name="sec1" id="sec1"></a>概念</h3>
<p class="first">当我们使用强参照（Strong reference）时，往往需要留意 <strong>循环参照</strong> 的问题。循环参照指的是两个对象被互相强参照，以至于任一对象都不能释放。</p>
<p>一般情况下，当对象之间有“父子关系”时，强参照的情况发生的比较多。比如通讯薄对象AddrBook和每个通讯录Entry的关系如下。</p>
<div class="imagebox">
<p><a href="http://www.yifeiyang.net/images/iphone/ARC/arc_reference_cycle_1.png" rel="lightbox[455]"><br />
<img src="http://www.yifeiyang.net/images/iphone/ARC/arc_reference_cycle_1.png" alt="arc_reference_cycle"/></a>
</p>
</div>
<p>这种情况下，由于Entry对象被AddrBook强参照，所以不能释放。另一方面，如果Entry被释放了，AddrBook对象的强参照也就没有了，其对象也应被释放。</p>
<h3><a name="sec2" id="sec2"></a>解决方式</h3>
<p class="first">像上面的例子，当多个对象间有“父子关系”时，需要在一侧用“弱参照”来解决循环参照问题。一般情况下，“父亲”作为“孩子”的拥有者，对“孩子”是强参照，而“孩子”对父亲是弱参照。</p>
<div class="imagebox">
<p><a href="http://www.yifeiyang.net/images/iphone/ARC/arc_reference_cycle_2.png" rel="lightbox[455]"><br />
<img src="http://www.yifeiyang.net/images/iphone/ARC/arc_reference_cycle_2.png" alt="arc_reference_cycle"/></a>
</p>
</div>
<p>如图所示，当强参照AddrBook对象的变量被释放的时候，AddrBook对象将被自动释放，同时将失去Entry成员对象的强参照。另外，当AddrBook对象被释放的时候，Entry对象中的AddrBook变量也将由Zeroing机制，自动带入nil。我们不需要担心释放对象的再访问问题。</p>
<p>下面，我们将看看有几种情况下，需要注意循环参照问题。</p>
<h4><a name="sec3" id="sec3"></a>Delegate模式</h4>
<p class="first">iOS程序中经常用到delegate模式，比如ViewController中，用ModalView打开/关闭DetailViewController时，需要delegate的设定。</p>
<div class="imagebox">
<p><a href="http://www.yifeiyang.net/images/iphone/ARC/arc_reference_cycle_3.png" rel="lightbox[455]"><br />
<img src="http://www.yifeiyang.net/images/iphone/ARC/arc_reference_cycle_3.png" alt="arc_reference_cycle"/></a>
</p>
</div>
<p>这里，ViewController对象中强参照detailViewController，如果DetailViewController的delegate不是弱参照ViewController话，将引起循环参照。</p>
<p>另外，当类中使用weak @property声明的delegate变量时，如果参照对象被释放，该变量将被自动设为nil，不需要程序代码设置。</p>
<h4><a name="sec4" id="sec4"></a>Blocks</h4>
<p class="first">Blocks是iOS 4开始导入的，可以理解为python或者lisp中的Lambda，C++11也已导入了该概念；类似概念ruby/smalltalk/JSP语言中也有定义。具体讲解见以后的文章，本节我们主要看看在Block中的循环参照问题。</p>
<p>比如，block对象用copy的属性定义时候，</p>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;"><span class="keyword">typedef</span> <span class="type">void</span>(^MyBlock)(<span class="type">void</span>);

<span class="keyword">@interface</span> <span class="type">MyObject</span> : <span class="type">NSObject</span>
@property (nonatomic, copy) <span class="type">MyBlock</span> <span class="variable-name">block</span>;
@property (nonatomic, strong) <span class="type">NSString</span> *<span class="variable-name">str</span>;

- (<span class="type">void</span>)<span class="function-name">performBlock</span>;
<span class="keyword">@end</span>

<span class="keyword">@implementation</span> <span class="type">MyObject</span>
<span class="type">@synthesize</span> <span class="type">block</span>, <span class="type">str</span>;

- (<span class="type">void</span>)<span class="function-name">performBlock</span> {
    <span class="keyword">if</span> (<span class="keyword">self</span>.block) {
        <span class="keyword">self</span>.block();
    }
}
<span class="keyword">@end</span>
</pre>
</td>
<tr></table>
</div>
<p>调用端如下：</p>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;"><span class="type">MyObject</span> *<span class="variable-name">object</span> = [[<span class="type">MyObject</span> alloc] init];
object.str = @<span class="string">"hoge"</span>;

object.block = ^{
    NSLog(@<span class="string">"block: str=%@"</span>, object.str);
};
[object performBlock];
</pre>
</td>
<tr></table>
</div>
<p>我们看到，Block的构文中参照了object，同样object也强参照block。</p>
<div class="imagebox">
<p><a href="http://www.yifeiyang.net/images/iphone/ARC/arc_reference_cycle_4.png" rel="lightbox[455]"><br />
<img src="http://www.yifeiyang.net/images/iphone/ARC/arc_reference_cycle_4.png" alt="arc_reference_cycle"/></a>
</p>
</div>
<p>为了解决该问题，我们可以有下面两种选择。</p>
<h5>使用__block关键字修饰</h5>
<p>使用__block关键字，让对象有读写权限，如果Block内的处理完毕就释放object。</p>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;">__block MyObject *object = [[<span class="type">MyObject</span> alloc] init];
object.str = @<span class="string">"hoge"</span>;

object.block = ^{
    NSLog(@<span class="string">"block: str=%@"</span>, object.str);
    object = <span class="constant">nil</span>;
};
[object performBlock];
</pre>
</td>
<tr></table>
</div>
<p>该关键字的意思就是让block取消对object的强参照，以避免循环参照。但是，有一个问题就是，object的释放动作是在Block内部执行，如果Block没有被执行的话，循环参照一直存在。比如上面的代码，如果第8行 [object performBlock]; 没有执行的话，那么一直还是循环参照状态。</p>
<h5>使用__weak关键字修饰</h5>
<p>另一种方案就是让Block的参照变为弱参照。</p>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;"><span class="type">MyObject</span> *<span class="variable-name">object</span> = [[<span class="type">MyObject</span> alloc] init];
object.str = @<span class="string">"hoge"</span>;

__weak MyObject *weakObject = object;
object.block = ^{
    NSLog(@<span class="string">"block: str=%@"</span>, weakObject.str);
};
[object performBlock];
</pre>
</td>
<tr></table>
</div>
<p>考虑到异步通信时Blocks的使用情况，weak变量weakObject有可能随时变为nil，所以类似于下面先变为strong变量，并检查是否为nil的处理方式应该更安全。</p>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
9
10
11
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;"><span class="type">MyObject</span> *<span class="variable-name">object</span> = [[<span class="type">MyObject</span> alloc] init];
object.str = @<span class="string">"hoge"</span>;

__weak MyObject *weakObject = object;
object.block = ^{
    <span class="type">MyObject</span> <span class="variable-name">strongObject</span> = weakObject;
    <span class="keyword">if</span> (strongObject) {
        NSLog(@<span class="string">"block: str=%@"</span>, strongObject.str);
    }
};
[object performBlock];
</pre>
</td>
<tr></table>
</div>
<p>总上，当我们使用Blocks时，也需要考虑Block中变量和实例的关系，不要引起不必要的循环参照问题。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.yifeiyang.net/development-of-the-iphone-simply-4/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>iPhone开发之深入浅出 (3) &#8212; ARC之前世今生</title>
		<link>http://www.yifeiyang.net/development-of-the-iphone-simply-3/</link>
		<comments>http://www.yifeiyang.net/development-of-the-iphone-simply-3/#comments</comments>
		<pubDate>Sun, 19 Feb 2012 10:45:41 +0000</pubDate>
		<dc:creator>yang</dc:creator>
				<category><![CDATA[ARC]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[深入浅出]]></category>
		<category><![CDATA[iOS]]></category>

		<guid isPermaLink="false">http://www.yifeiyang.net/?p=450</guid>
		<description><![CDATA[<div class="contents">
<dt>
<a href="#sec1">Objective-C 内存管理</a>
</dt>
<dd>
<dl>
<dt>
<a href="#sec2">基本原则</a>
</dt>
<dt>
<a href="#sec3">编程准则</a>
</dt>
</dl>
</dd>
<dt>
<a href="#sec4">ARC 诞生</a>
</dt>
<dd>
<dl>
<dt>
<a href="#sec5">__strong</a>
</dt>
<dt>
<a href="#sec6">__weak</a>
</dt>
<dt>
<a href="#sec7">__autoreleasing</a>
</dt>
<dt>
<a href="#sec8">ARC 规则</a>
</dt>
</dl>
</dd>
</div>



<p style="text-align: center;">
<strong>iPhone开发之深入浅出 (3) &#8212; ARC之前世今生</strong>
</p>

<p>前两节我们对 ARC(Automatic Reference Counting) 有了一个基本的理解，但是 ARC 是怎么产生的，为什么苹果要在其最新的 iOS/Mac OS X 上导入该框架？ 如果不理解其背后的基本原理，只是死记硬背那些规则/方法，是毫无意义的。就像我们从小接受的填鸭式教育，基本上到后来都还给老师了。</p>

<p>本节，我们先来看看 ARC 产生之前的 Objective-C 内存管理世界，然后再来看看导入 ARC 后，新的 LLVM 编译器在背后为我们做了什么。</p>

<h3><a name="sec1" id="sec1"></a>Objective-C 内存管理</h3>

<p class="first">和许多面向对象语言一样，Objective-C 中内存管理的方式其实就是指 <strong>引用计数</strong> （Reference Counting）的使用准则。如下图所示，对象生成的时候必定被某个持有者拿着，如果有多个持有者的话，其引用计数就会递增；相反失去一个持有者那么引用计数即会递减，直到失去所有的持有者，才真正地从内测中释放自己。</p>

<div class="imagebox">
<p><a href="http://www.yifeiyang.net/images/iphone/ARC/ARC1.png">
<img src="http://www.yifeiyang.net/images/iphone/ARC/ARC1.png" alt="ARC"/></a>
</p></div>

<h4><a name="sec2" id="sec2"></a>基本原则</h4>

<dl>
<dt><strong>内存管理的依循下面的基本原则</strong></dt><dd></dd>
</dl>

<ul>
<li>自己生成的对象，那么既是其持有者</li>
<li>不是自己生成的对象，也可成为其持有者（一个对象可以被多个人持有）</li>
<li>如果不想持有对象的时候，必须释放其所有权</li>
<li>不能释放已不再持有所有权的对象</li>
</ul>


<p>结合 Objective-C 语言中的方法，我们来看看基本的内存管理。</p>

<table class="muse-table" border="2" cellpadding="5">
  <thead>
    <tr>
      <th>方法</th>
      <th>动作</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>alloc/new/copy/mutableCopy</td>
      <td>生成对象并拥有所有权</td>
    </tr>
    <tr>
      <td>retain</td>
      <td>拥有对象所有权</td>
    </tr>
    <tr>
      <td>release</td>
      <td>释放对象所有权</td>
    </tr>
    <tr>
      <td>dealloc</td>
      <td>释放对象资源</td>
    </tr>
  </tbody>
</table>

<p>实际上这些函数并不能说是 Objective-C 语言所特有的，而是 OS X / iOS 系统库中包含的基类函数；具体说就是 Cocoa Framework::Foundation::NSObject 基类的成员函数。</p>

<p>Objective-C 语言内部严格遵守上面表格中的定义；首先是 alloc/new/copy/mutableCopy 这几个函数，并且是alloc/new/copy/mutableCopy 开头的函数，比如：allpcMyObject/newTheObject/copyThis/mutableCopyTheObject 等都必须遵循这个原则。</p>

<p>反而言之，如果不是 alloc/new/copy/mutableCopy 开头的函数，而且要返回对象的话，那么调用端只是生成对象，而不是其持有者。</p>

<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
9
10
11
</pre></td><td>
<pre class="src" style="color:#f5deb3;">-(<span class="type">id</span>)<span class="function-name">allocObject</span> {
    <span class="comment-delimiter">/*</span><span class="comment">
     * &#29983;&#25104;&#23545;&#35937;&#24182;&#25317;&#26377;&#25152;&#26377;&#26435;
     */</span>
    <span class="type">id</span> <span class="variable-name">obj</span> = [[<span class="type">NSObject</span> alloc] init];

    <span class="comment-delimiter">/*</span><span class="comment">
     * &#33258;&#24049;&#19968;&#30452;&#26159;&#25345;&#26377;&#23545;&#35937;&#29366;&#24577;
     */</span>
    <span class="keyword">return</span> obj;
}
</pre></td><tr></table></div>


<p>如上面的例子，alloc 生成的对象，其所有权会传递给函数的调用端；即满足了 alloc 开头函数的命名规则。</p>

<dl>
<dt><strong>再看下面的例子</strong></dt><dd></dd>
</dl>

<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td>
<pre class="src" style="color:#f5deb3;">-(<span class="type">id</span>)<span class="function-name">object</span> {
    <span class="type">id</span> <span class="variable-name">obj</span> = [[<span class="type">NSObject</span> alloc] init];

    <span class="comment-delimiter">/*</span><span class="comment">
     * &#33258;&#24049;&#19968;&#30452;&#26159;&#25345;&#26377;&#23545;&#35937;&#29366;&#24577;
     */</span>

    [obj autorelease];

    <span class="comment-delimiter">/*</span><span class="comment">
     * &#23545;&#35937;&#36824;&#23384;&#22312;&#65292;&#21482;&#26159;&#24182;&#19981;&#25345;&#26377;&#23427;&#30340;&#25152;&#26377;&#26435;
     */</span>

    <span class="keyword">return</span> obj;
}
</pre></td><tr></table></div>


<p>这里我们用到了 autorelease 函数。它的作用既是将对象放入 NSAutoreleasePool 中，由其来维护其生命周期。换句话说对象的持有者是 NSAutoreleasePool；上面的例子中，object 返回后，调用者将不持有其所有权。（除非再调用 retain。）</p>

<p>用 autorelease 的一个理由既是让程序员来控制对象的存活周期，而不像 C/C++ 等语言中，出栈后，栈中数据都被自动废弃，或者用 <strong>{ }</strong>  框住的自动变量，当出了范围就看不到了。在 Objective-C 中，只有当 [pool drain] 被调用的时候，才清空 pool 中所有登录的对象实体，在这之前，你可以像往常一样正常使用对象。</p>

<p>当然可以想象得到的，如果一个程序只有一个 NSAutoreleasePool，并在 main 中声明，程序结束时才 [pool drain]/[pool release] 的话，那么所有 autorelease 的对象都将塞满这个 pool，会耗掉系统大部分内存。所以，使用 NSAutoreleasePool 的时候也尽量建议局部使用，比如下面的循环。</p>

<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre></td><td>
<pre class="src" style="color:#f5deb3;"><span class="keyword">for</span> (i=0; i &#60; 100; i++) {
    <span class="type">NSAutoreleasePool</span>* <span class="variable-name">pool</span> = [[<span class="type">NSAutoreleasePool</span> alloc] init];

    <span class="comment-delimiter">// </span><span class="comment">&#19979;&#38754;&#30340;&#20989;&#25968;&#30001;&#20110;&#19981;&#23646;&#20110; alloc/new/copy/mutableCopy &#33539;&#30068;&#30340;&#20989;&#25968;&#65292;&#25152;&#20197;&#37117;&#20351;&#29992;&#20102; autorelease
</span>    <span class="type">NSMutableArray</span>* <span class="variable-name">array</span> = [<span class="type">NSMutableArray</span> array];
    <span class="type">NSString</span> *<span class="variable-name">str</span> = [<span class="type">NSString</span> stringWithFormat:@<span class="string">"TestCode"</span>];

    <span class="comment-delimiter">/*</span><span class="comment">
     * &#20854;&#20182;&#20351;&#29992;autorelease&#23450;&#20041;&#30340;&#23545;&#35937;
     */</span>
    <span class="type">Test</span> *<span class="variable-name">test</span> = [[[<span class="type">Test</span> alloc] init] autorelease];

    <span class="comment-delimiter">// </span><span class="comment">&#36890;&#36807;&#19979;&#38754;&#30340;&#20989;&#25968;&#65292;&#21487;&#20197;&#38543;&#26102;&#30417;&#25511;pool&#20013;&#30340;&#23545;&#35937;
</span>    <span class="comment-delimiter">// </span><span class="comment">iOS&#20197;&#22806;&#30340;&#36816;&#34892;&#24211;&#30340;&#24773;&#20917;&#19979;&#65292;&#20063;&#21487;&#20197;&#20351;&#29992; _objc_autoreleasePoolPrint() &#31169;&#26377;&#20989;&#25968;&#65292;&#21482;&#26159;&#38656;&#35201;&#19979;&#38754;&#30340;&#22768;&#26126;
</span>    <span class="comment-delimiter">// </span><span class="comment">extern void _objc_autoreleasePoolPrint();
</span>    [<span class="type">NSAutoreleasePool</span> showPools];

    <span class="comment-delimiter">// </span><span class="comment">&#36825;&#37324;&#25226;&#25152;&#26377;pool&#20013;&#30340;&#23545;&#35937;&#37117;&#37322;&#25918;&#25481;
</span>    [pool release];
}
</pre></td><tr></table></div>


<p>当然 NSAutoreleasePool 也可以嵌套，基本上都依存大括号规则。</p>


<h4><a name="sec3" id="sec3"></a>编程准则</h4>

<p class="first">基于以上原则，在 ARC 诞生之前，我们往往用下面准则来写代码。</p>

<h5>生成对象时，使用autorelease</h5>

<p>一般情况下，我们这样生成对象并使用</p>

<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
</pre></td><td>
<pre class="src" style="color:#f5deb3;"><span class="type">MyController</span>* <span class="variable-name">controller</span> = [[<span class="type">MyController</span> alloc] init];
<span class="comment-delimiter">// </span><span class="comment">......
</span>[controller release];
</pre></td><tr></table></div>


<p>如果在 [controller release] 之前函数return了怎么样，内存泄露了不是；为了防患于未然，一般像下面一样 <strong>生成对象时，使用autorelease</strong>。这样一来，该对象就被自动加入到最近的那个 pool 中。</p>

<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
</pre></td><td>
<pre class="src" style="color:#f5deb3;"><span class="type">MyController</span>* <span class="variable-name">controller</span> = [[[<span class="type">MyController</span> alloc] init] autorelease];
</pre></td><tr></table></div>



<h5>对象代入时，先autorelease后再retain</h5>

<p>对象代入的时候，如果之前不将变量所持有的对象释放，那么很可能引起内存泄露。比如下面的代码</p>

<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
9
10
11
12
</pre></td><td>
<pre class="src" style="color:#f5deb3;">{
  _member = [[<span class="type">TempValue</span> alloc] init];
}

- (<span class="type">void</span>)<span class="function-name">setValue</span>:(<span class="type">TempValue</span> *)<span class="variable-name">value</span> {
  _member = value;
  <span class="comment-delimiter">// </span><span class="comment">&#36825;&#26102;&#65292;&#20043;&#21069;&#25345;&#26377;&#30340;&#23545;&#35937;&#22240;&#20026;&#27809;&#26377; release &#32780;&#24341;&#36215;&#20869;&#23384;&#27844;&#38706;
</span>  <span class="comment-delimiter">// </span><span class="comment">&#24403;&#28982;&#65292;&#20808; [_member release] &#21518;&#20877;&#20195;&#20837;&#20063;&#26159;&#21487;&#20197;&#30340;&#65292;
</span>  <span class="comment-delimiter">// </span><span class="comment">&#20294;&#26159;&#24403;&#19982;&#12300;&#23545;&#35937;&#22312;&#20989;&#25968;&#20013;&#36820;&#22238;&#26102;&#12301;&#30340;&#38382;&#39064;&#19968;&#21516;&#32771;&#34385;&#26102;&#65292;
</span>  <span class="comment-delimiter">// </span><span class="comment">&#22914;&#26524;&#27809;&#26377; return [[object retain] autorelease] &#30340;&#20445;&#35777;&#65292;&#36825;&#37324;&#21363;&#20351; [_member release]&#20063;&#26159;&#30334;&#25645;
</span>  <span class="comment-delimiter">// </span><span class="comment">&#35814;&#32454;&#30340;&#35299;&#37322;&#35265;&#19979;
</span>}
</pre></td><tr></table></div>


<p>鉴于以上原因，我们将原先的对象先autorelease后再将新对象retain代入。</p>

<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
9
10
</pre></td><td>
<pre class="src" style="color:#f5deb3;">{
  _member = [[<span class="type">TempValue</span> alloc] init];
  <span class="comment-delimiter">// </span><span class="comment">&#36825;&#37324;&#65292;&#21363;&#20351;&#20351;&#29992;&#12304;&#29983;&#25104;&#23545;&#35937;&#26102;&#65292;&#20351;&#29992;autorelease&#12305;&#30340;&#20934;&#21017;&#65292;&#20063;&#27809;&#26377;&#20851;&#31995;
</span>  <span class="comment-delimiter">// </span><span class="comment">&#20351;&#29992;autorelease&#19968;&#27425;&#23601;&#23558;&#21046;&#23450;&#23545;&#35937;&#25918;&#20837;pool&#20013;&#65292;&#25918;&#20960;&#27425;[pool drain]&#30340;&#26102;&#20505;&#23601;&#37322;&#25918;&#20960;&#27425;
</span>}

- (<span class="type">void</span>)<span class="function-name">setValue</span>:(<span class="type">TempValue</span> *)<span class="variable-name">value</span> {
  [_member autorelease];
  _member = [value retain];
}
</pre></td><tr></table></div>


<p>该原则遵循 Failed Self 的原则，虽然从性能上看有所损耗但是保证了代码质量。</p>


<h5>对象在函数中返回时，使用return [[object retain] autorelease]</h5>

<p>严格地说，是除 alloc/new/copy/mutableCopy 开头函数以外的函数中，有对象放回时，使用return [[object retain] autorelease]。</p>

<dl>
<dt><strong>我们结合下面的例子来说明，并总结出该问题的几种解决方案</strong></dt><dd></dd>
</dl>

<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
</pre></td><td>
<pre class="src" style="color:#f5deb3;"><span class="keyword">@implementation</span> <span class="type">FooClass</span>

- (<span class="type">void</span>)<span class="function-name">setObject</span>:(<span class="type">MyObject</span> *)<span class="variable-name">object</span>;
 {
     <span class="comment-delimiter">// </span><span class="comment">&#36825;&#37324;&#25925;&#24847;&#27809;&#26377;&#20351;&#29992; autorelease&#65292;&#20197;&#20415;&#35828;&#26126;&#38382;&#39064;
</span>     [_object release];
     _object = [object retain];
 }

- (<span class="type">id</span>)<span class="function-name">object</span>;
 {
     <span class="keyword">return</span> _object;
 }

- (<span class="type">void</span>)<span class="function-name">dealloc</span>;
 {
     [_object release];
     [<span class="keyword">super</span> dealloc];
 }

<span class="keyword">@end</span>

<span class="keyword">@implementation</span> <span class="type">BarClass</span>

- (<span class="type">void</span>)<span class="function-name">doStuff</span>;
 {
    <span class="type">FooClass</span> * <span class="variable-name">foo</span> = [[<span class="type">FooClass</span> alloc] init];

    <span class="comment-delimiter">// </span><span class="comment">&#21019;&#24314;&#31532;&#19968;&#20010;&#23545;&#35937;&#65292;&#24341;&#29992;&#35745;&#25968; = 1
</span>    <span class="type">MyObject</span> * <span class="variable-name">firstObject</span> = [[<span class="type">MyObject</span> alloc] init];
    <span class="comment-delimiter">// </span><span class="comment">setObject&#20013;&#30001;&#20110; [object retain] &#65292;&#24341;&#29992;&#35745;&#25968; = 2
</span>    [foo setObject:firstObject];
    <span class="comment-delimiter">// </span><span class="comment">&#37322;&#25918;&#19968;&#27425;&#65292;&#24341;&#29992;&#35745;&#25968; = 1&#65307;&#36825;&#20043;&#21518;&#23545;&#35937;&#26377;&#27491;&#30830;&#30340;&#25152;&#26377;&#26435;&#23646;&#24615;
</span>    [firstObject release];

    <span class="comment-delimiter">// </span><span class="comment">&#36890;&#36807;&#38750; alloc/new/copy/mutableCopy &#24320;&#22836;&#20989;&#25968;&#24471;&#21040;&#23545;&#35937;
</span>    <span class="comment-delimiter">// </span><span class="comment">anObject &#25351;&#21521;&#31532;&#19968;&#20010;&#23545;&#35937;&#65292;&#20294;&#26159;&#24182;&#27809;&#26377;&#20854;&#25152;&#26377;&#26435;&#65292;&#23545;&#35937;&#24341;&#29992;&#35745;&#25968; = 1
</span>    <span class="type">MyObject</span> * <span class="variable-name">anObject</span> = [foo object];
    [anObject testMethod];

    <span class="comment-delimiter">// </span><span class="comment">&#21019;&#24314;&#31532;&#20108;&#20010;&#23545;&#35937;
</span>    <span class="type">MyObject</span> * <span class="variable-name">secondObject</span> = [[<span class="type">MyObject</span> alloc] init];
    <span class="comment-delimiter">// </span><span class="comment">setObject&#20013;&#30001;&#20110; [_object release]; &#31532;&#19968;&#20010;&#23545;&#35937;&#24341;&#29992;&#35745;&#25968; = 0&#65292;&#20869;&#23384;&#34987;&#37322;&#25918;
</span>    [foo setObject:secondObject];
    [secondObject release];

    <span class="comment-delimiter">// </span><span class="comment">&#31243;&#24207;&#22312;&#36825;&#37324;&#23849;&#28291;&#20102;&#65292;&#22240;&#20026; anObject &#25351;&#21521;&#20102;&#19968;&#20010;&#31354;&#22320;&#22336;
</span>    [anObject testMethod];
}

<span class="keyword">@end</span>
</pre></td><tr></table></div>


<p>从结论我们来看看该问题的几种可行的解决方案；各种方案中没有列出的代码与原先代码一致。</p>

<dl>
<dt><strong>生成对象时，使用autorelease</strong></dt><dd></dd>
</dl>

<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre></td><td>
<pre class="src" style="color:#f5deb3;"><span class="keyword">@implementation</span> <span class="type">BarClass</span>

- (<span class="type">void</span>)<span class="function-name">doStuff</span>;
 {
    <span class="type">FooClass</span> * <span class="variable-name">foo</span> = [[<span class="type">FooClass</span> alloc] init];

    <span class="type">MyObject</span> * <span class="variable-name">firstObject</span> = [[[<span class="type">MyObject</span> alloc] init] autorelease];
    [foo setObject:firstObject];

    <span class="type">MyObject</span> * <span class="variable-name">anObject</span> = [foo object];
    [anObject testMethod];

    <span class="type">MyObject</span> * <span class="variable-name">secondObject</span> = [[[<span class="type">MyObject</span> alloc] init] autorelease];
    [foo setObject:secondObject];

    [anObject testMethod];
}

<span class="keyword">@end</span>
</pre></td><tr></table></div>


<p>对象生成时，即被放入最近的 pool 中，不需要人为特殊的维护，对象的生命周期将被延续，出 <strong>{}</strong> 范围之时即对象释放之际。</p>


<dl>
<dt><strong>对象代入时，先autorelease后再retain</strong></dt><dd></dd>
</dl>

<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
9
10
11
</pre></td><td>
<pre class="src" style="color:#f5deb3;">- (<span class="type">void</span>)<span class="function-name">setObject</span>:(<span class="type">MyObject</span> *)<span class="variable-name">object</span>;
 {
     [_object autorelease];
     _object = [object retain];
 }

- (<span class="type">id</span>)<span class="function-name">object</span>;
 {
     <span class="comment-delimiter">// </span><span class="comment">&#36981;&#24490;&#38750; alloc/new/copy/mutableCopy &#24320;&#22836;&#30340;&#20989;&#25968;&#65292;&#19981;&#36176;&#20104;&#25152;&#26377;&#26435;&#21407;&#21017;
</span>     <span class="keyword">return</span> _object;
 }
</pre></td><tr></table></div>


<p>同样的，对象被放入最近的 pool 中，第二次 setObject 后对象引用计数仍为1， pool 清空时才执行最后一次对象release，从而保证了代码的正确性。</p>

<dl>
<dt><strong>对象在函数中返回时，使用return [[object retain] autorelease];</strong></dt><dd></dd>
</dl>

<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
9
10
11
</pre></td><td>
<pre class="src" style="color:#f5deb3;">- (<span class="type">void</span>)<span class="function-name">setObject</span>:(<span class="type">MyObject</span> *)<span class="variable-name">object</span>;
 {
     [_object release];
     _object = [object retain];
 }

- (<span class="type">id</span>)<span class="function-name">object</span>;
 {
     <span class="comment-delimiter">// </span><span class="comment">&#36981;&#24490;&#38750; alloc/new/copy/mutableCopy &#24320;&#22836;&#30340;&#20989;&#25968;&#65292;&#19981;&#36176;&#20104;&#25152;&#26377;&#26435;&#21407;&#21017;
</span>     <span class="keyword">return</span> [[_object retain] autorelease];
 }
</pre></td><tr></table></div>


<p>好不容易回到了本小节要说明的方法；可以看到这是从另一个角度解决了该问题：[foo object] 的时候保证引用计数是2，并将对象放入pool中维护。</p>

<p>总结上面上面3中方法，虽说是从不同角度入手解决了这个问题，但是基本原则不变，利用 NSAutoreleasePool 机制帮程序员维护代码，管理内存。</p>

<p>如果你觉得3种编码原则怎么搭配使用，在什么样的场合下选择比较麻烦，不要紧，都用就得了。我们牺牲的只是 NSAutoreleasePool 中的一些内存，一小许性能损失罢了，这总比我们的程序崩溃了强。</p>




<h3><a name="sec4" id="sec4"></a>ARC 诞生</h3>

<p class="first">ARC 是什么我不需要再解释，若有不明白，可以看<a href="http://www.yifeiyang.net/development-of-the-iphone-simply-1/">iPhone开发之深入浅出 (1) — ARC是什么</a>。</p>

<dl>
<dt><strong>ARC 严格遵守 Objective-C 内存管理的基本原则</strong></dt><dd></dd>
</dl>

<ul>
<li>自己生成的对象，那么既是其持有者</li>
<li>不是自己生成的对象，也可成为其持有者（一个对象可以被多个人持有）</li>
<li>如果不想持有对象的时候，必须释放其所有权</li>
<li>不能释放已不再持有所有权的对象</li>
</ul>

<p>并从编译器角度维护了该原则，比如如果不是 alloc/new/copy/mutableCopy 开头的函数，编译器会将生成的对象自动放入 autoReleasePool 中。如果是 __strong 修饰的变量，编译器会自动给其加上所有权。等等，详细，我们根据不同的关键字来看看编译器为我们具体做了什么。并从中总结出 ARC 的使用规则。</p>

<h4><a name="sec5" id="sec5"></a>__strong</h4>

<p class="first">我们先来看看用 __strong 修饰的变量，以及缺省隐藏的 __strong 情况。</p>

<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td>
<pre class="src" style="color:#f5deb3;">{
    <span class="comment-delimiter">/*</span><span class="comment">
     * &#29983;&#25104;&#23545;&#35937;&#24182;&#25317;&#26377;&#25152;&#26377;&#26435;
     */</span>
    <span class="type">id</span> __strong obj = [[<span class="type">NSObject</span> alloc] init];

    <span class="comment-delimiter">/*</span><span class="comment">
     * &#33258;&#24049;&#19968;&#30452;&#26159;&#25345;&#26377;&#23545;&#35937;&#29366;&#24577;
     */</span>
}
    <span class="comment-delimiter">/*</span><span class="comment">
     * &#21464;&#37327;&#20986;&#29983;&#21629;&#21608;&#26399;&#26102;&#65292;&#22833;&#21435;&#20840;&#37096;&#25152;&#26377;&#32773;&#65292;&#23545;&#35937;&#20869;&#23384;&#31354;&#38388;&#34987;&#37322;&#25918;
     */</span>
</pre></td><tr></table></div>


<p>这种情况毫无悬念，缺省使用 alloc/new/copy/mutableCopy 开头的函数也是这样的结果。并且在这里，编译器帮我们自动的调用了对象的 release 函数，不需要手工维护。再看看下面的情况。</p>

<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre></td><td>
<pre class="src" style="color:#f5deb3;">{
    <span class="comment-delimiter">/*</span><span class="comment">
     * &#29983;&#25104;&#23545;&#35937;&#20294;&#26159;&#24182;&#27809;&#26377;&#20854;&#25152;&#26377;&#26435;
     */</span>
    <span class="type">id</span> __strong obj = [<span class="type">NSMutableArray</span> array];

    <span class="comment-delimiter">/*</span><span class="comment">
     * &#30001;&#20110;&#21464;&#37327;&#22768;&#26126;&#26159;&#24378;&#24341;&#29992;&#65292;&#33258;&#24049;&#19968;&#30452;&#26159;&#25345;&#26377;&#23545;&#35937;&#29366;&#24577;
     * &#32534;&#35793;&#22120;&#26681;&#25454;&#20989;&#25968;&#21517;&#65292;&#20877;&#23558;&#35813;&#23545;&#35937;&#25918;&#20837; autoreleasepool &#20013;
     */</span>
}
    <span class="comment-delimiter">/*</span><span class="comment">
     * &#21464;&#37327;&#20986;&#29983;&#21629;&#21608;&#26399;&#26102;&#65292;&#22833;&#21435;&#20840;&#37096;&#25152;&#26377;&#32773;&#65292;&#23545;&#35937;&#20869;&#23384;&#31354;&#38388;&#34987;&#37322;&#25918;
     */</span>
</pre></td><tr></table></div>


<p>由上，虽然不是用 alloc/new/copy/mutableCopy 开头的函数得到的对象，由于是强参照，我们任然成为对象的持有者。而这，正是编译器帮我们做到的。</p>

<blockquote>
<p class="quoted">具体做的是什么呢？其实就是【对象在函数中返回时，使用return [[object retain] autorelease]】所描述的；如果你反汇编一下ARC生成的代码，可以看到这时会自动调用名为 objc_retainAutoreleaseReturnValue 的函数，而其作用和 [[object retain] autorelease] 一致。编译器通过函数名分析，如果不是 alloc/new/copy/mutableCopy 开头的函数，自动加入了这段代码。</p>
</blockquote>

<p>另外，缺省 __strong 修饰的变量，对象代入的时候也正确地保证对象所有者规则；代入新对象时，自动释放旧对象的参照，代入nil的时候，表示释放当前对象的强参照。</p>


<h4><a name="sec6" id="sec6"></a>__weak</h4>

<p class="first">虽然大部分场合，大部分问题使用 __strong 来编码就足够了；但是为了解决循环参照的问题 __weak 关键字修饰【弱参照】变量就发挥了左右。关于循环参照的问题，准备在以后的博文中介绍；今天，主要看看编译器在背后怎么处理 __weak 变量的。</p>

<p>__weak 声明的变量其实是被放入一个weak表中，该表和引用计数的表格类似，是一个Hash表，都是以对象的内存地址做key，同时，针对一个对象地址的key，可以同时对应多个变量的地址。</p>

<dl>
<dt><strong>当一个 __weak 所指对象被释放时，系统按下面步骤来处理</strong></dt><dd></dd>
</dl>

<ul>
<li>从weak表中，通过对象地址（key）找到entry</li>
<li>将entry中所有指向该对象的变量设为nil</li>
<li>从weak表中删除该entry</li>
<li>从对象引用计数表中删除对象entry(通过通过对象地址找到)</li>
</ul>

<p>另外，当使用 __weak 修饰的变量的时候，变量将放入 autoreleasepool 中，并且用几次放几次。比如下面的简单例子。</p>

<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
</pre></td><td>
<pre class="src" style="color:#f5deb3;">{
    <span class="type">id</span> __weak o = obj;
    NSLog(@<span class="string">"1 %@"</span>, o);
    NSLog(@<span class="string">"2 %@"</span>, o);
    NSLog(@<span class="string">"3 %@"</span>, o);
    NSLog(@<span class="string">"4 %@"</span>, o);
    NSLog(@<span class="string">"5 %@"</span>, o);
}
</pre></td><tr></table></div>


<p>这里我们用了5次，那么pool中就被登录了5次；从效率上考虑这样当然不是很好，可以通过代入 __strong 修饰的强参照变量来避开这个问题。</p>

<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
9
</pre></td><td>
<pre class="src" style="color:#f5deb3;">{
    <span class="type">id</span> __weak o = obj;
    <span class="type">id</span> <span class="variable-name">temp</span> = o;
    NSLog(@<span class="string">"1 %@"</span>, temp);
    NSLog(@<span class="string">"2 %@"</span>, temp);
    NSLog(@<span class="string">"3 %@"</span>, temp);
    NSLog(@<span class="string">"4 %@"</span>, temp);
    NSLog(@<span class="string">"5 %@"</span>, temp);
}
</pre></td><tr></table></div>


<p>另外，还有通过重载 allowsWeakReference/retainWeakReference 函数来限制 __weak 声明变量使用回数的方法，毕竟不在本次讨论范畴之内，就此省略。</p>

<p>话说回来，为什么使用弱参照变量的时候，要将其放入 autoreleasepool 中呢？想想弱参照的定义就应该明白了 &#8212;- 如果在访问弱参照对象时，该对象被释放了怎么办，程序不就崩溃了嘛；所以为了解决该问题，又再一次用到了 pool。</p>


<h4><a name="sec7" id="sec7"></a>__autoreleasing</h4>

<p class="first">虽然上面还没有降到该关键字，但是编译器在很多时候已经用到了 autoreleasepool。比如非 alloc/new/copy/mutableCopy 开头的函数返回一个对象的时候，又比如使用一个 __weak 声明的变量的时候。</p>

<p>实际上，写ARC代码的时候，明示 __autoreleasing 声明变量和明示 __strong 声明变量一样基本上没有，因为编译器已经为我们做了很多，很智能了（前提是我们要按ARC的规则写代码）。</p>

<p>还有一种编译器缺省使用 __autoreleasing 关键字声明变量的时候：对象指针类型。比如下面的对应关系。</p>

<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
</pre></td><td>
<pre class="src" style="color:#f5deb3;">   <span class="type">id</span> *<span class="variable-name">obj</span> == <span class="type">id</span> __autoreleasing *obj
   NSObject **obj == NSObject * __autoreleasing *obj
</pre></td><tr></table></div>


<p>所以，下面两个函数的是等价的。</p>

<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
</pre></td><td>
<pre class="src" style="color:#f5deb3;">-(<span class="type">BOOL</span>)<span class="function-name">performOperationWithError</span>:(<span class="type">NSError</span> **)<span class="variable-name">error</span>;

-(<span class="type">BOOL</span>)<span class="function-name">performOperationWithError</span>:(<span class="type">NSError</span> * __autoreleasing *)<span class="variable-name">error</span>;
</pre></td><tr></table></div>


<p>像下面的函数调用，为什么是可行的呢？</p>

<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
</pre></td><td>
<pre class="src" style="color:#f5deb3;">NSError __strong *error = <span class="constant">nil</span>;
<span class="type">BOOL</span> <span class="variable-name">result</span> = [obj performOperationWithError:&#38;error];
</pre></td><tr></table></div>


<p>其实，编译器是这样解释这段代码的。</p>

<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
</pre></td><td>
<pre class="src" style="color:#f5deb3;">NSError __strong *error = <span class="constant">nil</span>;
NSError __autoreleasing *tmp = error;
<span class="type">BOOL</span> <span class="variable-name">result</span> = [obj performOperationWithError:&#38;tmp];
error = tmp;
</pre></td><tr></table></div>


<p>那么我们这样声明函数不就可以了吗？</p>

<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
</pre></td><td>
<pre class="src" style="color:#f5deb3;">-(<span class="type">BOOL</span>)<span class="function-name">performOperationWithError</span>:(<span class="type">NSError</span> * __strong *)<span class="variable-name">error</span>;
</pre></td><tr></table></div>


<p>答案是肯定的，你可以这样做，编译是可以通过，但你违反了非 alloc/new/copy/mutableCopy 开头的函数，不返回对象持有权的原则。这里是没有问题了，但也许影响到其他地方NG。</p>


<h4><a name="sec8" id="sec8"></a>ARC 规则</h4>

<dl>
<dt><strong>结合上面的讲解，我想你也应该能够总结出来使用ARC时的规则</strong></dt><dd></dd>
</dl>

<p>（这里只列出本讲中涉及的内容，其他的内容以后总结）</p>

<ul>
<li>代码中不能使用retain, release, retain, autorelease</li>
<li>不能使用NSAllocateObject, NSDeallocateObject</li>
<li>不能使用NSAutoReleasePool、而需要@autoreleasepool块</li>
<li>严守内存管理相关函数命名规则</li>
</ul>

<p>关于函数命名，伴随ARC的导入，还有一系列函数的定义也被严格定义了，那就是以 init 开头的函数。init 函数作为alloc生成对象的初期化函数，需要按原样直接传递对象给调用段，所以下面的声明是OK的。</p>

<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
</pre></td><td>
<pre class="src" style="color:#f5deb3;">-(<span class="type">id</span>)<span class="function-name">initWithObject</span>:(<span class="type">id</span>)<span class="variable-name">obj</span>;
</pre></td><tr></table></div>


<p>而下面的是NG的。</p>

<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
</pre></td><td>
<pre class="src" style="color:#f5deb3;">-(<span class="type">void</span>)<span class="function-name">initWithObject</span>;
</pre></td><tr></table></div>


<p>不过声明为 -(void) initialize; 是没有问题的。</p>]]></description>
			<content:encoded><![CDATA[<div class="contents">
<dt>
<a href="#sec1">Objective-C 内存管理</a>
</dt>
<dd>
<dl>
<dt>
<a href="#sec2">基本原则</a>
</dt>
<dt>
<a href="#sec3">编程准则</a>
</dt>
</dl>
</dd>
<dt>
<a href="#sec4">ARC 诞生</a>
</dt>
<dd>
<dl>
<dt>
<a href="#sec5">__strong</a>
</dt>
<dt>
<a href="#sec6">__weak</a>
</dt>
<dt>
<a href="#sec7">__autoreleasing</a>
</dt>
<dt>
<a href="#sec8">ARC 规则</a>
</dt>
</dl>
</dd>
</div>
<p style="text-align: center;">
<strong>iPhone开发之深入浅出 (3) &mdash; ARC之前世今生</strong>
</p>
<p>前两节我们对 ARC(Automatic Reference Counting) 有了一个基本的理解，但是 ARC 是怎么产生的，为什么苹果要在其最新的 iOS/Mac OS X 上导入该框架？ 如果不理解其背后的基本原理，只是死记硬背那些规则/方法，是毫无意义的。就像我们从小接受的填鸭式教育，基本上到后来都还给老师了。</p>
<p>本节，我们先来看看 ARC 产生之前的 Objective-C 内存管理世界，然后再来看看导入 ARC 后，新的 LLVM 编译器在背后为我们做了什么。</p>
<h3><a name="sec1" id="sec1"></a>Objective-C 内存管理</h3>
<p class="first">和许多面向对象语言一样，Objective-C 中内存管理的方式其实就是指 <strong>引用计数</strong> （Reference Counting）的使用准则。如下图所示，对象生成的时候必定被某个持有者拿着，如果有多个持有者的话，其引用计数就会递增；相反失去一个持有者那么引用计数即会递减，直到失去所有的持有者，才真正地从内测中释放自己。</p>
<div class="imagebox">
<p><a href="http://www.yifeiyang.net/images/iphone/ARC/ARC1.png" rel="lightbox[450]"><br />
<img src="http://www.yifeiyang.net/images/iphone/ARC/ARC1.png" alt="ARC"/></a>
</p>
</div>
<h4><a name="sec2" id="sec2"></a>基本原则</h4>
<dl>
<dt><strong>内存管理的依循下面的基本原则</strong></dt>
<dd></dd>
</dl>
<ul>
<li>自己生成的对象，那么既是其持有者</li>
<li>不是自己生成的对象，也可成为其持有者（一个对象可以被多个人持有）</li>
<li>如果不想持有对象的时候，必须释放其所有权</li>
<li>不能释放已不再持有所有权的对象</li>
</ul>
<p>结合 Objective-C 语言中的方法，我们来看看基本的内存管理。</p>
<table class="muse-table" border="2" cellpadding="5">
<thead>
<tr>
<th>方法</th>
<th>动作</th>
</tr>
</thead>
<tbody>
<tr>
<td>alloc/new/copy/mutableCopy</td>
<td>生成对象并拥有所有权</td>
</tr>
<tr>
<td>retain</td>
<td>拥有对象所有权</td>
</tr>
<tr>
<td>release</td>
<td>释放对象所有权</td>
</tr>
<tr>
<td>dealloc</td>
<td>释放对象资源</td>
</tr>
</tbody>
</table>
<p>实际上这些函数并不能说是 Objective-C 语言所特有的，而是 OS X / iOS 系统库中包含的基类函数；具体说就是 Cocoa Framework::Foundation::NSObject 基类的成员函数。</p>
<p>Objective-C 语言内部严格遵守上面表格中的定义；首先是 alloc/new/copy/mutableCopy 这几个函数，并且是alloc/new/copy/mutableCopy 开头的函数，比如：allpcMyObject/newTheObject/copyThis/mutableCopyTheObject 等都必须遵循这个原则。</p>
<p>反而言之，如果不是 alloc/new/copy/mutableCopy 开头的函数，而且要返回对象的话，那么调用端只是生成对象，而不是其持有者。</p>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
9
10
11
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;">-(<span class="type">id</span>)<span class="function-name">allocObject</span> {
    <span class="comment-delimiter">/*</span><span class="comment">
     * &#29983;&#25104;&#23545;&#35937;&#24182;&#25317;&#26377;&#25152;&#26377;&#26435;
     */</span>
    <span class="type">id</span> <span class="variable-name">obj</span> = [[<span class="type">NSObject</span> alloc] init];

    <span class="comment-delimiter">/*</span><span class="comment">
     * &#33258;&#24049;&#19968;&#30452;&#26159;&#25345;&#26377;&#23545;&#35937;&#29366;&#24577;
     */</span>
    <span class="keyword">return</span> obj;
}
</pre>
</td>
<tr></table>
</div>
<p>如上面的例子，alloc 生成的对象，其所有权会传递给函数的调用端；即满足了 alloc 开头函数的命名规则。</p>
<dl>
<dt><strong>再看下面的例子</strong></dt>
<dd></dd>
</dl>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;">-(<span class="type">id</span>)<span class="function-name">object</span> {
    <span class="type">id</span> <span class="variable-name">obj</span> = [[<span class="type">NSObject</span> alloc] init];

    <span class="comment-delimiter">/*</span><span class="comment">
     * &#33258;&#24049;&#19968;&#30452;&#26159;&#25345;&#26377;&#23545;&#35937;&#29366;&#24577;
     */</span>

    [obj autorelease];

    <span class="comment-delimiter">/*</span><span class="comment">
     * &#23545;&#35937;&#36824;&#23384;&#22312;&#65292;&#21482;&#26159;&#24182;&#19981;&#25345;&#26377;&#23427;&#30340;&#25152;&#26377;&#26435;
     */</span>

    <span class="keyword">return</span> obj;
}
</pre>
</td>
<tr></table>
</div>
<p>这里我们用到了 autorelease 函数。它的作用既是将对象放入 NSAutoreleasePool 中，由其来维护其生命周期。换句话说对象的持有者是 NSAutoreleasePool；上面的例子中，object 返回后，调用者将不持有其所有权。（除非再调用 retain。）</p>
<p>用 autorelease 的一个理由既是让程序员来控制对象的存活周期，而不像 C/C++ 等语言中，出栈后，栈中数据都被自动废弃，或者用 <strong>{ }</strong>  框住的自动变量，当出了范围就看不到了。在 Objective-C 中，只有当 [pool drain] 被调用的时候，才清空 pool 中所有登录的对象实体，在这之前，你可以像往常一样正常使用对象。</p>
<p>当然可以想象得到的，如果一个程序只有一个 NSAutoreleasePool，并在 main 中声明，程序结束时才 [pool drain]/[pool release] 的话，那么所有 autorelease 的对象都将塞满这个 pool，会耗掉系统大部分内存。所以，使用 NSAutoreleasePool 的时候也尽量建议局部使用，比如下面的循环。</p>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;"><span class="keyword">for</span> (i=0; i &lt; 100; i++) {
    <span class="type">NSAutoreleasePool</span>* <span class="variable-name">pool</span> = [[<span class="type">NSAutoreleasePool</span> alloc] init];

    <span class="comment-delimiter">// </span><span class="comment">&#19979;&#38754;&#30340;&#20989;&#25968;&#30001;&#20110;&#19981;&#23646;&#20110; alloc/new/copy/mutableCopy &#33539;&#30068;&#30340;&#20989;&#25968;&#65292;&#25152;&#20197;&#37117;&#20351;&#29992;&#20102; autorelease
</span>    <span class="type">NSMutableArray</span>* <span class="variable-name">array</span> = [<span class="type">NSMutableArray</span> array];
    <span class="type">NSString</span> *<span class="variable-name">str</span> = [<span class="type">NSString</span> stringWithFormat:@<span class="string">"TestCode"</span>];

    <span class="comment-delimiter">/*</span><span class="comment">
     * &#20854;&#20182;&#20351;&#29992;autorelease&#23450;&#20041;&#30340;&#23545;&#35937;
     */</span>
    <span class="type">Test</span> *<span class="variable-name">test</span> = [[[<span class="type">Test</span> alloc] init] autorelease];

    <span class="comment-delimiter">// </span><span class="comment">&#36890;&#36807;&#19979;&#38754;&#30340;&#20989;&#25968;&#65292;&#21487;&#20197;&#38543;&#26102;&#30417;&#25511;pool&#20013;&#30340;&#23545;&#35937;
</span>    <span class="comment-delimiter">// </span><span class="comment">iOS&#20197;&#22806;&#30340;&#36816;&#34892;&#24211;&#30340;&#24773;&#20917;&#19979;&#65292;&#20063;&#21487;&#20197;&#20351;&#29992; _objc_autoreleasePoolPrint() &#31169;&#26377;&#20989;&#25968;&#65292;&#21482;&#26159;&#38656;&#35201;&#19979;&#38754;&#30340;&#22768;&#26126;
</span>    <span class="comment-delimiter">// </span><span class="comment">extern void _objc_autoreleasePoolPrint();
</span>    [<span class="type">NSAutoreleasePool</span> showPools];

    <span class="comment-delimiter">// </span><span class="comment">&#36825;&#37324;&#25226;&#25152;&#26377;pool&#20013;&#30340;&#23545;&#35937;&#37117;&#37322;&#25918;&#25481;
</span>    [pool release];
}
</pre>
</td>
<tr></table>
</div>
<p>当然 NSAutoreleasePool 也可以嵌套，基本上都依存大括号规则。</p>
<h4><a name="sec3" id="sec3"></a>编程准则</h4>
<p class="first">基于以上原则，在 ARC 诞生之前，我们往往用下面准则来写代码。</p>
<h5>生成对象时，使用autorelease</h5>
<p>一般情况下，我们这样生成对象并使用</p>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;"><span class="type">MyController</span>* <span class="variable-name">controller</span> = [[<span class="type">MyController</span> alloc] init];
<span class="comment-delimiter">// </span><span class="comment">......
</span>[controller release];
</pre>
</td>
<tr></table>
</div>
<p>如果在 [controller release] 之前函数return了怎么样，内存泄露了不是；为了防患于未然，一般像下面一样 <strong>生成对象时，使用autorelease</strong>。这样一来，该对象就被自动加入到最近的那个 pool 中。</p>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;"><span class="type">MyController</span>* <span class="variable-name">controller</span> = [[[<span class="type">MyController</span> alloc] init] autorelease];
</pre>
</td>
<tr></table>
</div>
<h5>对象代入时，先autorelease后再retain</h5>
<p>对象代入的时候，如果之前不将变量所持有的对象释放，那么很可能引起内存泄露。比如下面的代码</p>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
9
10
11
12
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;">{
  _member = [[<span class="type">TempValue</span> alloc] init];
}

- (<span class="type">void</span>)<span class="function-name">setValue</span>:(<span class="type">TempValue</span> *)<span class="variable-name">value</span> {
  _member = value;
  <span class="comment-delimiter">// </span><span class="comment">&#36825;&#26102;&#65292;&#20043;&#21069;&#25345;&#26377;&#30340;&#23545;&#35937;&#22240;&#20026;&#27809;&#26377; release &#32780;&#24341;&#36215;&#20869;&#23384;&#27844;&#38706;
</span>  <span class="comment-delimiter">// </span><span class="comment">&#24403;&#28982;&#65292;&#20808; [_member release] &#21518;&#20877;&#20195;&#20837;&#20063;&#26159;&#21487;&#20197;&#30340;&#65292;
</span>  <span class="comment-delimiter">// </span><span class="comment">&#20294;&#26159;&#24403;&#19982;&#12300;&#23545;&#35937;&#22312;&#20989;&#25968;&#20013;&#36820;&#22238;&#26102;&#12301;&#30340;&#38382;&#39064;&#19968;&#21516;&#32771;&#34385;&#26102;&#65292;
</span>  <span class="comment-delimiter">// </span><span class="comment">&#22914;&#26524;&#27809;&#26377; return [[object retain] autorelease] &#30340;&#20445;&#35777;&#65292;&#36825;&#37324;&#21363;&#20351; [_member release]&#20063;&#26159;&#30334;&#25645;
</span>  <span class="comment-delimiter">// </span><span class="comment">&#35814;&#32454;&#30340;&#35299;&#37322;&#35265;&#19979;
</span>}
</pre>
</td>
<tr></table>
</div>
<p>鉴于以上原因，我们将原先的对象先autorelease后再将新对象retain代入。</p>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
9
10
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;">{
  _member = [[<span class="type">TempValue</span> alloc] init];
  <span class="comment-delimiter">// </span><span class="comment">&#36825;&#37324;&#65292;&#21363;&#20351;&#20351;&#29992;&#12304;&#29983;&#25104;&#23545;&#35937;&#26102;&#65292;&#20351;&#29992;autorelease&#12305;&#30340;&#20934;&#21017;&#65292;&#20063;&#27809;&#26377;&#20851;&#31995;
</span>  <span class="comment-delimiter">// </span><span class="comment">&#20351;&#29992;autorelease&#19968;&#27425;&#23601;&#23558;&#21046;&#23450;&#23545;&#35937;&#25918;&#20837;pool&#20013;&#65292;&#25918;&#20960;&#27425;[pool drain]&#30340;&#26102;&#20505;&#23601;&#37322;&#25918;&#20960;&#27425;
</span>}

- (<span class="type">void</span>)<span class="function-name">setValue</span>:(<span class="type">TempValue</span> *)<span class="variable-name">value</span> {
  [_member autorelease];
  _member = [value retain];
}
</pre>
</td>
<tr></table>
</div>
<p>该原则遵循 Failed Self 的原则，虽然从性能上看有所损耗但是保证了代码质量。</p>
<h5>对象在函数中返回时，使用return [[object retain] autorelease]</h5>
<p>严格地说，是除 alloc/new/copy/mutableCopy 开头函数以外的函数中，有对象放回时，使用return [[object retain] autorelease]。</p>
<dl>
<dt><strong>我们结合下面的例子来说明，并总结出该问题的几种解决方案</strong></dt>
<dd></dd>
</dl>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;"><span class="keyword">@implementation</span> <span class="type">FooClass</span>

- (<span class="type">void</span>)<span class="function-name">setObject</span>:(<span class="type">MyObject</span> *)<span class="variable-name">object</span>;
 {
     <span class="comment-delimiter">// </span><span class="comment">&#36825;&#37324;&#25925;&#24847;&#27809;&#26377;&#20351;&#29992; autorelease&#65292;&#20197;&#20415;&#35828;&#26126;&#38382;&#39064;
</span>     [_object release];
     _object = [object retain];
 }

- (<span class="type">id</span>)<span class="function-name">object</span>;
 {
     <span class="keyword">return</span> _object;
 }

- (<span class="type">void</span>)<span class="function-name">dealloc</span>;
 {
     [_object release];
     [<span class="keyword">super</span> dealloc];
 }

<span class="keyword">@end</span>

<span class="keyword">@implementation</span> <span class="type">BarClass</span>

- (<span class="type">void</span>)<span class="function-name">doStuff</span>;
 {
    <span class="type">FooClass</span> * <span class="variable-name">foo</span> = [[<span class="type">FooClass</span> alloc] init];

    <span class="comment-delimiter">// </span><span class="comment">&#21019;&#24314;&#31532;&#19968;&#20010;&#23545;&#35937;&#65292;&#24341;&#29992;&#35745;&#25968; = 1
</span>    <span class="type">MyObject</span> * <span class="variable-name">firstObject</span> = [[<span class="type">MyObject</span> alloc] init];
    <span class="comment-delimiter">// </span><span class="comment">setObject&#20013;&#30001;&#20110; [object retain] &#65292;&#24341;&#29992;&#35745;&#25968; = 2
</span>    [foo setObject:firstObject];
    <span class="comment-delimiter">// </span><span class="comment">&#37322;&#25918;&#19968;&#27425;&#65292;&#24341;&#29992;&#35745;&#25968; = 1&#65307;&#36825;&#20043;&#21518;&#23545;&#35937;&#26377;&#27491;&#30830;&#30340;&#25152;&#26377;&#26435;&#23646;&#24615;
</span>    [firstObject release];

    <span class="comment-delimiter">// </span><span class="comment">&#36890;&#36807;&#38750; alloc/new/copy/mutableCopy &#24320;&#22836;&#20989;&#25968;&#24471;&#21040;&#23545;&#35937;
</span>    <span class="comment-delimiter">// </span><span class="comment">anObject &#25351;&#21521;&#31532;&#19968;&#20010;&#23545;&#35937;&#65292;&#20294;&#26159;&#24182;&#27809;&#26377;&#20854;&#25152;&#26377;&#26435;&#65292;&#23545;&#35937;&#24341;&#29992;&#35745;&#25968; = 1
</span>    <span class="type">MyObject</span> * <span class="variable-name">anObject</span> = [foo object];
    [anObject testMethod];

    <span class="comment-delimiter">// </span><span class="comment">&#21019;&#24314;&#31532;&#20108;&#20010;&#23545;&#35937;
</span>    <span class="type">MyObject</span> * <span class="variable-name">secondObject</span> = [[<span class="type">MyObject</span> alloc] init];
    <span class="comment-delimiter">// </span><span class="comment">setObject&#20013;&#30001;&#20110; [_object release]; &#31532;&#19968;&#20010;&#23545;&#35937;&#24341;&#29992;&#35745;&#25968; = 0&#65292;&#20869;&#23384;&#34987;&#37322;&#25918;
</span>    [foo setObject:secondObject];
    [secondObject release];

    <span class="comment-delimiter">// </span><span class="comment">&#31243;&#24207;&#22312;&#36825;&#37324;&#23849;&#28291;&#20102;&#65292;&#22240;&#20026; anObject &#25351;&#21521;&#20102;&#19968;&#20010;&#31354;&#22320;&#22336;
</span>    [anObject testMethod];
}

<span class="keyword">@end</span>
</pre>
</td>
<tr></table>
</div>
<p>从结论我们来看看该问题的几种可行的解决方案；各种方案中没有列出的代码与原先代码一致。</p>
<dl>
<dt><strong>生成对象时，使用autorelease</strong></dt>
<dd></dd>
</dl>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;"><span class="keyword">@implementation</span> <span class="type">BarClass</span>

- (<span class="type">void</span>)<span class="function-name">doStuff</span>;
 {
    <span class="type">FooClass</span> * <span class="variable-name">foo</span> = [[<span class="type">FooClass</span> alloc] init];

    <span class="type">MyObject</span> * <span class="variable-name">firstObject</span> = [[[<span class="type">MyObject</span> alloc] init] autorelease];
    [foo setObject:firstObject];

    <span class="type">MyObject</span> * <span class="variable-name">anObject</span> = [foo object];
    [anObject testMethod];

    <span class="type">MyObject</span> * <span class="variable-name">secondObject</span> = [[[<span class="type">MyObject</span> alloc] init] autorelease];
    [foo setObject:secondObject];

    [anObject testMethod];
}

<span class="keyword">@end</span>
</pre>
</td>
<tr></table>
</div>
<p>对象生成时，即被放入最近的 pool 中，不需要人为特殊的维护，对象的生命周期将被延续，出 <strong>{}</strong> 范围之时即对象释放之际。</p>
<dl>
<dt><strong>对象代入时，先autorelease后再retain</strong></dt>
<dd></dd>
</dl>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
9
10
11
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;">- (<span class="type">void</span>)<span class="function-name">setObject</span>:(<span class="type">MyObject</span> *)<span class="variable-name">object</span>;
 {
     [_object autorelease];
     _object = [object retain];
 }

- (<span class="type">id</span>)<span class="function-name">object</span>;
 {
     <span class="comment-delimiter">// </span><span class="comment">&#36981;&#24490;&#38750; alloc/new/copy/mutableCopy &#24320;&#22836;&#30340;&#20989;&#25968;&#65292;&#19981;&#36176;&#20104;&#25152;&#26377;&#26435;&#21407;&#21017;
</span>     <span class="keyword">return</span> _object;
 }
</pre>
</td>
<tr></table>
</div>
<p>同样的，对象被放入最近的 pool 中，第二次 setObject 后对象引用计数仍为1， pool 清空时才执行最后一次对象release，从而保证了代码的正确性。</p>
<dl>
<dt><strong>对象在函数中返回时，使用return [[object retain] autorelease];</strong></dt>
<dd></dd>
</dl>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
9
10
11
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;">- (<span class="type">void</span>)<span class="function-name">setObject</span>:(<span class="type">MyObject</span> *)<span class="variable-name">object</span>;
 {
     [_object release];
     _object = [object retain];
 }

- (<span class="type">id</span>)<span class="function-name">object</span>;
 {
     <span class="comment-delimiter">// </span><span class="comment">&#36981;&#24490;&#38750; alloc/new/copy/mutableCopy &#24320;&#22836;&#30340;&#20989;&#25968;&#65292;&#19981;&#36176;&#20104;&#25152;&#26377;&#26435;&#21407;&#21017;
</span>     <span class="keyword">return</span> [[_object retain] autorelease];
 }
</pre>
</td>
<tr></table>
</div>
<p>好不容易回到了本小节要说明的方法；可以看到这是从另一个角度解决了该问题：[foo object] 的时候保证引用计数是2，并将对象放入pool中维护。</p>
<p>总结上面上面3中方法，虽说是从不同角度入手解决了这个问题，但是基本原则不变，利用 NSAutoreleasePool 机制帮程序员维护代码，管理内存。</p>
<p>如果你觉得3种编码原则怎么搭配使用，在什么样的场合下选择比较麻烦，不要紧，都用就得了。我们牺牲的只是 NSAutoreleasePool 中的一些内存，一小许性能损失罢了，这总比我们的程序崩溃了强。</p>
<h3><a name="sec4" id="sec4"></a>ARC 诞生</h3>
<p class="first">ARC 是什么我不需要再解释，若有不明白，可以看<a href="http://www.yifeiyang.net/development-of-the-iphone-simply-1/">iPhone开发之深入浅出 (1) — ARC是什么</a>。</p>
<dl>
<dt><strong>ARC 严格遵守 Objective-C 内存管理的基本原则</strong></dt>
<dd></dd>
</dl>
<ul>
<li>自己生成的对象，那么既是其持有者</li>
<li>不是自己生成的对象，也可成为其持有者（一个对象可以被多个人持有）</li>
<li>如果不想持有对象的时候，必须释放其所有权</li>
<li>不能释放已不再持有所有权的对象</li>
</ul>
<p>并从编译器角度维护了该原则，比如如果不是 alloc/new/copy/mutableCopy 开头的函数，编译器会将生成的对象自动放入 autoReleasePool 中。如果是 __strong 修饰的变量，编译器会自动给其加上所有权。等等，详细，我们根据不同的关键字来看看编译器为我们具体做了什么。并从中总结出 ARC 的使用规则。</p>
<h4><a name="sec5" id="sec5"></a>__strong</h4>
<p class="first">我们先来看看用 __strong 修饰的变量，以及缺省隐藏的 __strong 情况。</p>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
9
10
11
12
13
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;">{
    <span class="comment-delimiter">/*</span><span class="comment">
     * &#29983;&#25104;&#23545;&#35937;&#24182;&#25317;&#26377;&#25152;&#26377;&#26435;
     */</span>
    <span class="type">id</span> __strong obj = [[<span class="type">NSObject</span> alloc] init];

    <span class="comment-delimiter">/*</span><span class="comment">
     * &#33258;&#24049;&#19968;&#30452;&#26159;&#25345;&#26377;&#23545;&#35937;&#29366;&#24577;
     */</span>
}
    <span class="comment-delimiter">/*</span><span class="comment">
     * &#21464;&#37327;&#20986;&#29983;&#21629;&#21608;&#26399;&#26102;&#65292;&#22833;&#21435;&#20840;&#37096;&#25152;&#26377;&#32773;&#65292;&#23545;&#35937;&#20869;&#23384;&#31354;&#38388;&#34987;&#37322;&#25918;
     */</span>
</pre>
</td>
<tr></table>
</div>
<p>这种情况毫无悬念，缺省使用 alloc/new/copy/mutableCopy 开头的函数也是这样的结果。并且在这里，编译器帮我们自动的调用了对象的 release 函数，不需要手工维护。再看看下面的情况。</p>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;">{
    <span class="comment-delimiter">/*</span><span class="comment">
     * &#29983;&#25104;&#23545;&#35937;&#20294;&#26159;&#24182;&#27809;&#26377;&#20854;&#25152;&#26377;&#26435;
     */</span>
    <span class="type">id</span> __strong obj = [<span class="type">NSMutableArray</span> array];

    <span class="comment-delimiter">/*</span><span class="comment">
     * &#30001;&#20110;&#21464;&#37327;&#22768;&#26126;&#26159;&#24378;&#24341;&#29992;&#65292;&#33258;&#24049;&#19968;&#30452;&#26159;&#25345;&#26377;&#23545;&#35937;&#29366;&#24577;
     * &#32534;&#35793;&#22120;&#26681;&#25454;&#20989;&#25968;&#21517;&#65292;&#20877;&#23558;&#35813;&#23545;&#35937;&#25918;&#20837; autoreleasepool &#20013;
     */</span>
}
    <span class="comment-delimiter">/*</span><span class="comment">
     * &#21464;&#37327;&#20986;&#29983;&#21629;&#21608;&#26399;&#26102;&#65292;&#22833;&#21435;&#20840;&#37096;&#25152;&#26377;&#32773;&#65292;&#23545;&#35937;&#20869;&#23384;&#31354;&#38388;&#34987;&#37322;&#25918;
     */</span>
</pre>
</td>
<tr></table>
</div>
<p>由上，虽然不是用 alloc/new/copy/mutableCopy 开头的函数得到的对象，由于是强参照，我们任然成为对象的持有者。而这，正是编译器帮我们做到的。</p>
<blockquote>
<p class="quoted">具体做的是什么呢？其实就是【对象在函数中返回时，使用return [[object retain] autorelease]】所描述的；如果你反汇编一下ARC生成的代码，可以看到这时会自动调用名为 objc_retainAutoreleaseReturnValue 的函数，而其作用和 [[object retain] autorelease] 一致。编译器通过函数名分析，如果不是 alloc/new/copy/mutableCopy 开头的函数，自动加入了这段代码。</p>
</blockquote>
<p>另外，缺省 __strong 修饰的变量，对象代入的时候也正确地保证对象所有者规则；代入新对象时，自动释放旧对象的参照，代入nil的时候，表示释放当前对象的强参照。</p>
<h4><a name="sec6" id="sec6"></a>__weak</h4>
<p class="first">虽然大部分场合，大部分问题使用 __strong 来编码就足够了；但是为了解决循环参照的问题 __weak 关键字修饰【弱参照】变量就发挥了左右。关于循环参照的问题，准备在以后的博文中介绍；今天，主要看看编译器在背后怎么处理 __weak 变量的。</p>
<p>__weak 声明的变量其实是被放入一个weak表中，该表和引用计数的表格类似，是一个Hash表，都是以对象的内存地址做key，同时，针对一个对象地址的key，可以同时对应多个变量的地址。</p>
<dl>
<dt><strong>当一个 __weak 所指对象被释放时，系统按下面步骤来处理</strong></dt>
<dd></dd>
</dl>
<ul>
<li>从weak表中，通过对象地址（key）找到entry</li>
<li>将entry中所有指向该对象的变量设为nil</li>
<li>从weak表中删除该entry</li>
<li>从对象引用计数表中删除对象entry(通过通过对象地址找到)</li>
</ul>
<p>另外，当使用 __weak 修饰的变量的时候，变量将放入 autoreleasepool 中，并且用几次放几次。比如下面的简单例子。</p>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;">{
    <span class="type">id</span> __weak o = obj;
    NSLog(@<span class="string">"1 %@"</span>, o);
    NSLog(@<span class="string">"2 %@"</span>, o);
    NSLog(@<span class="string">"3 %@"</span>, o);
    NSLog(@<span class="string">"4 %@"</span>, o);
    NSLog(@<span class="string">"5 %@"</span>, o);
}
</pre>
</td>
<tr></table>
</div>
<p>这里我们用了5次，那么pool中就被登录了5次；从效率上考虑这样当然不是很好，可以通过代入 __strong 修饰的强参照变量来避开这个问题。</p>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
9
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;">{
    <span class="type">id</span> __weak o = obj;
    <span class="type">id</span> <span class="variable-name">temp</span> = o;
    NSLog(@<span class="string">"1 %@"</span>, temp);
    NSLog(@<span class="string">"2 %@"</span>, temp);
    NSLog(@<span class="string">"3 %@"</span>, temp);
    NSLog(@<span class="string">"4 %@"</span>, temp);
    NSLog(@<span class="string">"5 %@"</span>, temp);
}
</pre>
</td>
<tr></table>
</div>
<p>另外，还有通过重载 allowsWeakReference/retainWeakReference 函数来限制 __weak 声明变量使用回数的方法，毕竟不在本次讨论范畴之内，就此省略。</p>
<p>话说回来，为什么使用弱参照变量的时候，要将其放入 autoreleasepool 中呢？想想弱参照的定义就应该明白了 &mdash;- 如果在访问弱参照对象时，该对象被释放了怎么办，程序不就崩溃了嘛；所以为了解决该问题，又再一次用到了 pool。</p>
<h4><a name="sec7" id="sec7"></a>__autoreleasing</h4>
<p class="first">虽然上面还没有降到该关键字，但是编译器在很多时候已经用到了 autoreleasepool。比如非 alloc/new/copy/mutableCopy 开头的函数返回一个对象的时候，又比如使用一个 __weak 声明的变量的时候。</p>
<p>实际上，写ARC代码的时候，明示 __autoreleasing 声明变量和明示 __strong 声明变量一样基本上没有，因为编译器已经为我们做了很多，很智能了（前提是我们要按ARC的规则写代码）。</p>
<p>还有一种编译器缺省使用 __autoreleasing 关键字声明变量的时候：对象指针类型。比如下面的对应关系。</p>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;">   <span class="type">id</span> *<span class="variable-name">obj</span> == <span class="type">id</span> __autoreleasing *obj
   NSObject **obj == NSObject * __autoreleasing *obj
</pre>
</td>
<tr></table>
</div>
<p>所以，下面两个函数的是等价的。</p>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;">-(<span class="type">BOOL</span>)<span class="function-name">performOperationWithError</span>:(<span class="type">NSError</span> **)<span class="variable-name">error</span>;

-(<span class="type">BOOL</span>)<span class="function-name">performOperationWithError</span>:(<span class="type">NSError</span> * __autoreleasing *)<span class="variable-name">error</span>;
</pre>
</td>
<tr></table>
</div>
<p>像下面的函数调用，为什么是可行的呢？</p>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;">NSError __strong *error = <span class="constant">nil</span>;
<span class="type">BOOL</span> <span class="variable-name">result</span> = [obj performOperationWithError:&amp;error];
</pre>
</td>
<tr></table>
</div>
<p>其实，编译器是这样解释这段代码的。</p>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;">NSError __strong *error = <span class="constant">nil</span>;
NSError __autoreleasing *tmp = error;
<span class="type">BOOL</span> <span class="variable-name">result</span> = [obj performOperationWithError:&amp;tmp];
error = tmp;
</pre>
</td>
<tr></table>
</div>
<p>那么我们这样声明函数不就可以了吗？</p>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;">-(<span class="type">BOOL</span>)<span class="function-name">performOperationWithError</span>:(<span class="type">NSError</span> * __strong *)<span class="variable-name">error</span>;
</pre>
</td>
<tr></table>
</div>
<p>答案是肯定的，你可以这样做，编译是可以通过，但你违反了非 alloc/new/copy/mutableCopy 开头的函数，不返回对象持有权的原则。这里是没有问题了，但也许影响到其他地方NG。</p>
<h4><a name="sec8" id="sec8"></a>ARC 规则</h4>
<dl>
<dt><strong>结合上面的讲解，我想你也应该能够总结出来使用ARC时的规则</strong></dt>
<dd></dd>
</dl>
<p>（这里只列出本讲中涉及的内容，其他的内容以后总结）</p>
<ul>
<li>代码中不能使用retain, release, retain, autorelease</li>
<li>不能使用NSAllocateObject, NSDeallocateObject</li>
<li>不能使用NSAutoReleasePool、而需要@autoreleasepool块</li>
<li>严守内存管理相关函数命名规则</li>
</ul>
<p>关于函数命名，伴随ARC的导入，还有一系列函数的定义也被严格定义了，那就是以 init 开头的函数。init 函数作为alloc生成对象的初期化函数，需要按原样直接传递对象给调用段，所以下面的声明是OK的。</p>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;">-(<span class="type">id</span>)<span class="function-name">initWithObject</span>:(<span class="type">id</span>)<span class="variable-name">obj</span>;
</pre>
</td>
<tr></table>
</div>
<p>而下面的是NG的。</p>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;">-(<span class="type">void</span>)<span class="function-name">initWithObject</span>;
</pre>
</td>
<tr></table>
</div>
<p>不过声明为 -(void) initialize; 是没有问题的。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.yifeiyang.net/development-of-the-iphone-simply-3/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>iPhone开发技巧之发布篇（7）&#8212;  制作自己的Cydia发布源</title>
		<link>http://www.yifeiyang.net/iphone-release-of-developing-skills-paper-7/</link>
		<comments>http://www.yifeiyang.net/iphone-release-of-developing-skills-paper-7/#comments</comments>
		<pubDate>Fri, 20 Jan 2012 02:07:00 +0000</pubDate>
		<dc:creator>yang</dc:creator>
				<category><![CDATA[发布篇]]></category>
		<category><![CDATA[开发技巧]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[muse]]></category>

		<guid isPermaLink="false">http://www.yifeiyang.net/iphone%e5%bc%80%e5%8f%91%e6%8a%80%e5%b7%a7%e4%b9%8b%e5%8f%91%e5%b8%83%e7%af%87%ef%bc%887%ef%bc%89-%e5%88%b6%e4%bd%9c%e8%87%aa%e5%b7%b1%e7%9a%84cydia%e5%8f%91%e5%b8%83%e6%ba%90/</guid>
		<description><![CDATA[<div class="contents"><dt> <a href="#sec1">Linux Debian</a> </dt> <dt> <a href="#sec2">脚本工具</a> </dt> <dt> <a href="#sec3">制作deb文件</a> </dt> <dt> <a href="#sec4">制作Repository</a> </dt></div>
<p style="text-align: center;"><strong>iPhone开发技巧之发布篇（7）— 制作自己的Cydia发布源</strong></p>

针对越狱的iPhone，大家肯定都知道用Cydia来安装各种免费应用的经历。Cydia中是否能指定我们自己的发布源，让我们自己随心所欲地发布程序给别人呢？答案是肯定的，我们只要创建Cydia的发布repository即可。
<h4><a id="sec1" name="sec1"></a>Linux Debian</h4>
<p class="first">首先，我们需要有<a href="http://www.debian.org">Linux Debian</a>或者<a href="http://www.ubuntulinux.jp/products/GetUbuntu">Ubuntu</a>系统来制作Cydia的发布源。如果你没有Linux Debian系统的机器，不要紧，可以随时用VMware Player或VirtualBox虚拟机来安装一个。</p>

安装的时候用i386的iso即可，如果是64bit的OS用amd64的image来安装。安装的时候，选择Graphical Install，其他缺省安装。
<h4><a id="sec2" name="sec2"></a>脚本工具</h4>
<p class="first">下载下面两个脚本文件到本地，并加上可执行属性。</p>

<ul>
	<li>下载<a href="http://www.yifeiyang.net/download/iphone/cydia/dpkg-scanpackages">dpkg-scanpackages</a>到/usr/bin</li>
	<li>下载<a href="http://www.yifeiyang.net/download/iphone/cydia/dpkg-gettext.pl">dpkg-gettext.pl</a>到/etc/perl。</li>
</ul>
<h4><a id="sec3" name="sec3"></a>制作deb文件</h4>
<dl> <dt><strong>以名称为MyProgram的程序微粒，首先在home目录下建立下面的目录结构</strong></dt> <dd></dd> </dl>
<div class="codebox">
<table border="0" width="100%">
<tbody>
<tr>
<td class="line_numbers">
<pre>1
2
3
4
5
6
7
8
9
10</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;">Cydia
   +- MyProgram
      +- DEBIAN
      &#124;  +- control
      +- var
         +- mobile
            +- MyProgram.app
                +- Info.plist
                +- MyProgram
                +- icon.png</pre>
</td>
</tr>
</tbody></table>
</div>
可以看出来，我们需要把程序MyProgram安装到/var/mobile/中去.

DEBIAN目录下面有一个名为control的文件，我们来看看它的内容。
<div class="codebox">
<table border="0" width="100%">
<tbody>
<tr>
<td class="line_numbers">
<pre>1
2
3
4
5
6
7
8
9</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;">Package: net.yifeiyang.MyProgram
Name: MyProgram
Version: 1.0.4-1
Architecture: iphoneos-arm
Description: test text.
Homepage: http://www.yifeiyang.net
Maintainer: YIFEIYANG &#60;kane_yj@hotmail.com&#62;
Author: YIFEIYANG &#60;kane_yj@hotmail.com&#62;
Section: Games</pre>
</td>
</tr>
</tbody></table>
</div>
<table class="muse-table" border="2" cellpadding="5">
<thead>
<tr>
<th>名称</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>Package</td>
<td>唯一标示Package的名称，一般用「域名.Package名」</td>
</tr>
<tr>
<td>Name</td>
<td>程序的名称</td>
</tr>
<tr>
<td>Version</td>
<td>程序版本，不能使用字母</td>
</tr>
<tr>
<td>Architecture</td>
<td>固定为iphoneos-arm</td>
</tr>
<tr>
<td>Description</td>
<td>程序概要说明，将显示在Cydia的说明页内</td>
</tr>
<tr>
<td>Homepage</td>
<td>程序网页</td>
</tr>
<tr>
<td>Maintainer</td>
<td>维护者名称，邮箱</td>
</tr>
<tr>
<td>Author</td>
<td>作者，邮箱</td>
</tr>
<tr>
<td>Section</td>
<td>所属类型，设定了之后，程序名旁边将显示具体的icon</td>
</tr>
</tbody></table>
<dl> <dt><strong>编译在制作DEB文件很简单，只需要</strong></dt> <dd></dd> </dl>
<div class="codebox">
<table border="0" width="100%">
<tbody>
<tr>
<td class="line_numbers">
<pre>1
2</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;"><span class="builtin">cd</span> ~/Cydia
dpkg-deb –b MyProgram</pre>
</td>
</tr>
</tbody></table>
</div>
这之后，我们就可以试试该deb文件，用iFile将文件上传到iPhone上并安装，查看/var/mobile/下的情况。这里我们可以使用<a href="http://www.yifeiyang.net/iphone-release-of-developing-skills-paper-6/">iPhone开发技巧之发布篇（6）— 不需Developper认证的真机调试方法</a>中的方法制作我们的程序，从而不需要验证信息。
<h4><a id="sec4" name="sec4"></a>制作Repository</h4>
<dl> <dt><strong>每次追加新的deb文件，或者是deb文件有更新时，需要做下面两步</strong></dt> <dd></dd> </dl>
<div class="codebox">
<table border="0" width="100%">
<tbody>
<tr>
<td class="line_numbers">
<pre>1
2</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;">dpkg-scanpackages –m . /dev/null &#62;Packages
bzip2 Packages</pre>
</td>
</tr>
</tbody></table>
</div>
OK了，接下来我们就可以把Packages.bz2和MyProgram.deb这两个文件上传到你的web服务器中，然后把地址作为Source添加到Cydia中就搞定了。如果没有web服务器也没有关系，可以使用Dropbox等共享网盘，得到唯一的一个URL即可。]]></description>
			<content:encoded><![CDATA[<div class="contents">
<dt> <a href="#sec1">Linux Debian</a> </dt>
<dt> <a href="#sec2">脚本工具</a> </dt>
<dt> <a href="#sec3">制作deb文件</a> </dt>
<dt> <a href="#sec4">制作Repository</a> </dt>
</div>
<p style="text-align: center;"><strong>iPhone开发技巧之发布篇（7）— 制作自己的Cydia发布源</strong></p>
<p>针对越狱的iPhone，大家肯定都知道用Cydia来安装各种免费应用的经历。Cydia中是否能指定我们自己的发布源，让我们自己随心所欲地发布程序给别人呢？答案是肯定的，我们只要创建Cydia的发布repository即可。</p>
<h4><a id="sec1" name="sec1"></a>Linux Debian</h4>
<p class="first">首先，我们需要有<a href="http://www.debian.org">Linux Debian</a>或者<a href="http://www.ubuntulinux.jp/products/GetUbuntu">Ubuntu</a>系统来制作Cydia的发布源。如果你没有Linux Debian系统的机器，不要紧，可以随时用VMware Player或VirtualBox虚拟机来安装一个。</p>
<p>安装的时候用i386的iso即可，如果是64bit的OS用amd64的image来安装。安装的时候，选择Graphical Install，其他缺省安装。</p>
<h4><a id="sec2" name="sec2"></a>脚本工具</h4>
<p class="first">下载下面两个脚本文件到本地，并加上可执行属性。</p>
<ul>
<li>下载<a href="http://www.yifeiyang.net/download/iphone/cydia/dpkg-scanpackages">dpkg-scanpackages</a>到/usr/bin</li>
<li>下载<a href="http://www.yifeiyang.net/download/iphone/cydia/dpkg-gettext.pl">dpkg-gettext.pl</a>到/etc/perl。</li>
</ul>
<h4><a id="sec3" name="sec3"></a>制作deb文件</h4>
<dl>
<dt><strong>以名称为MyProgram的程序微粒，首先在home目录下建立下面的目录结构</strong></dt>
<dd></dd>
</dl>
<div class="codebox">
<table border="0" width="100%">
<tbody>
<tr>
<td class="line_numbers">
<pre>1
2
3
4
5
6
7
8
9
10</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;">Cydia
   +- MyProgram
      +- DEBIAN
      |  +- control
      +- var
         +- mobile
            +- MyProgram.app
                +- Info.plist
                +- MyProgram
                +- icon.png</pre>
</td>
</tr>
</tbody>
</table>
</div>
<p>可以看出来，我们需要把程序MyProgram安装到/var/mobile/中去.</p>
<p>DEBIAN目录下面有一个名为control的文件，我们来看看它的内容。</p>
<div class="codebox">
<table border="0" width="100%">
<tbody>
<tr>
<td class="line_numbers">
<pre>1
2
3
4
5
6
7
8
9</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;">Package: net.yifeiyang.MyProgram
Name: MyProgram
Version: 1.0.4-1
Architecture: iphoneos-arm
Description: test text.
Homepage: http://www.yifeiyang.net
Maintainer: YIFEIYANG &lt;kane_yj@hotmail.com&gt;
Author: YIFEIYANG &lt;kane_yj@hotmail.com&gt;
Section: Games</pre>
</td>
</tr>
</tbody>
</table>
</div>
<table class="muse-table" border="2" cellpadding="5">
<thead>
<tr>
<th>名称</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>Package</td>
<td>唯一标示Package的名称，一般用「域名.Package名」</td>
</tr>
<tr>
<td>Name</td>
<td>程序的名称</td>
</tr>
<tr>
<td>Version</td>
<td>程序版本，不能使用字母</td>
</tr>
<tr>
<td>Architecture</td>
<td>固定为iphoneos-arm</td>
</tr>
<tr>
<td>Description</td>
<td>程序概要说明，将显示在Cydia的说明页内</td>
</tr>
<tr>
<td>Homepage</td>
<td>程序网页</td>
</tr>
<tr>
<td>Maintainer</td>
<td>维护者名称，邮箱</td>
</tr>
<tr>
<td>Author</td>
<td>作者，邮箱</td>
</tr>
<tr>
<td>Section</td>
<td>所属类型，设定了之后，程序名旁边将显示具体的icon</td>
</tr>
</tbody>
</table>
<dl>
<dt><strong>编译在制作DEB文件很简单，只需要</strong></dt>
<dd></dd>
</dl>
<div class="codebox">
<table border="0" width="100%">
<tbody>
<tr>
<td class="line_numbers">
<pre>1
2</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;"><span class="builtin">cd</span> ~/Cydia
dpkg-deb –b MyProgram</pre>
</td>
</tr>
</tbody>
</table>
</div>
<p>这之后，我们就可以试试该deb文件，用iFile将文件上传到iPhone上并安装，查看/var/mobile/下的情况。这里我们可以使用<a href="http://www.yifeiyang.net/iphone-release-of-developing-skills-paper-6/">iPhone开发技巧之发布篇（6）— 不需Developper认证的真机调试方法</a>中的方法制作我们的程序，从而不需要验证信息。</p>
<h4><a id="sec4" name="sec4"></a>制作Repository</h4>
<dl>
<dt><strong>每次追加新的deb文件，或者是deb文件有更新时，需要做下面两步</strong></dt>
<dd></dd>
</dl>
<div class="codebox">
<table border="0" width="100%">
<tbody>
<tr>
<td class="line_numbers">
<pre>1
2</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;">dpkg-scanpackages –m . /dev/null &gt;Packages
bzip2 Packages</pre>
</td>
</tr>
</tbody>
</table>
</div>
<p>OK了，接下来我们就可以把Packages.bz2和MyProgram.deb这两个文件上传到你的web服务器中，然后把地址作为Source添加到Cydia中就搞定了。如果没有web服务器也没有关系，可以使用Dropbox等共享网盘，得到唯一的一个URL即可。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.yifeiyang.net/iphone-release-of-developing-skills-paper-7/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>iPhone开发之深入浅出 (2) &#8212; ARC之@property使用</title>
		<link>http://www.yifeiyang.net/development-of-the-iphone-simply-2/</link>
		<comments>http://www.yifeiyang.net/development-of-the-iphone-simply-2/#comments</comments>
		<pubDate>Wed, 04 Jan 2012 00:22:00 +0000</pubDate>
		<dc:creator>yang</dc:creator>
				<category><![CDATA[ARC]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[深入浅出]]></category>
		<category><![CDATA[muse]]></category>
		<category><![CDATA[Objective-C]]></category>

		<guid isPermaLink="false">http://www.yifeiyang.net/iphone%e5%bc%80%e5%8f%91%e4%b9%8b%e6%b7%b1%e5%85%a5%e6%b5%85%e5%87%ba-2-arc%e4%b9%8bproperty%e4%bd%bf%e7%94%a8/</guid>
		<description><![CDATA[<dt> <a href="#sec1">所有者属性</a> </dt> <dt> <a href="#sec2">读写相关的属性 (readwrite, readonly)</a> </dt> </div>    <p style="text-align: center;"> <strong>iPhone开发之深入浅出 (2) &#8212; ARC之@property使用</strong> </p>   <p>上一回我们学到了一些ARC的基本概念，这一次我们来看看ARC对@property的使用规则有何影响。</p>  <h4></span><a name="sec1" id="sec1"></a>所有者属性</h4>  <p class="first">我们先来看看与所有权有关系的属性，关键字间的对应关系。</p>  <table class="muse-table" border="2" cellpadding="5">   <thead>     <tr>       <th>属性值</th>       <th>关键字</th>       <th>所有权</th>     </tr>   </thead>   <tbody>     <tr>       <td>strong</td>       <td>__strong</td>       <td>有</td>     </tr>     <tr>       <td>weak</td>       <td>__weak</td>       <td>无</td>     </tr>     <tr>       <td>unsafe_unretained</td>       <td>__unsafe_unretained</td>       <td>无</td>     </tr>     <tr>       <td>copy</td>       <td>__strong</td>       <td>有</td>     </tr>     <tr>       <td>assign</td>       <td>__unsafe_unretained</td>       <td>无</td>     </tr>     <tr>       <td>retain</td>       <td>__strong</td>       <td>有</td>     </tr>   </tbody> </table>  <dl> <dt><strong>strong</strong></dt><dd>  <p>该属性值对应 __strong 关键字，即该属性所声明的变量将成为对象的持有者。</p></dd>  <dt><strong>weak</strong></dt><dd>  <p>该属性对应 __weak 关键字，与 __weak 定义的变量一致，该属性所声明的变量将没有对象的所有权，并且当对象被破弃之后，对象将被自动赋值nil。</p>  <p>并且，delegate 和 Outlet 应该用 weak 属性来声明。同时，如上一回介绍的 iOS 5 之前的版本是没有 __weak 关键字的，所以 weak 属性是不能使用的。这种情况我们使用 unsafe_unretained。</p></dd>  <dt><strong>unsafe_unretained</strong></dt><dd>  <p>等效于__unsafe_unretaind关键字声明的变量；像上面说明的，iOS 5之前的系统用该属性代替 weak 来使用。</p></dd>  <dt><strong>copy</strong></dt><dd>  <p>与 strong 的区别是声明变量是拷贝对象的持有者。</p></dd>  <dt><strong>assign</strong></dt><dd>  <p>一般Scalar Varible用该属性声明，比如,int, BOOL。</p></dd>  <dt><strong>retain</strong></dt><dd>  <p>该属性与 strong 一致；只是可读性更强一些。</p></dd> </dl>   <h4></span><a name="sec2" id="sec2"></a>读写相关的属性 (readwrite, readonly)</h4>  <p class="first">读写相关的属性有 readwrite 和 readonly 两种，如果使用ARC之后，我么需要注意一下 readonly 属性的使用。</p>  <p>比如下面的变量声明。</p>  <div class="codebox"> <table width="100%"> <tr> <td class="line_numbers"> <pre>
1
</pre></td><td>
<pre class="src" style="color:#f5deb3;">@property (nonatomic, readonly) <span class="type">NSString</span> *<span class="variable-name">name</span>;
</pre></td><tr></table></div>


<p>一般声明为 readonly 的变量按理说应该不需要持有所有权了，但是在ARC有效的情况下，将出现下面的错误信息 ：</p>

<blockquote>
<p class="quoted">“ARC forbids synthesizing a property of an Objective-C object with unspecified ownership or storage attribute”</p>
</blockquote>

<p><strong>如果定义了ARC有效，那么必须要有所有者属性的定义</strong>；所以我们的代码改成这样，就OK了</p>

<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
</pre></td><td>
<pre class="src" style="color:#f5deb3;">@property (nonatomic, strong, readonly) <span class="type">NSString</span> *<span class="variable-name">name</span>;
</pre></td><tr></table></div>


<p>不过有一点，Scalar Varible的变量缺省都有 assign 的属性定义，所以不需要给他们单独的明示声明了。</p>]]></description>
			<content:encoded><![CDATA[<dt> <a href="#sec1">所有者属性</a> </dt>
<dt> <a href="#sec2">读写相关的属性 (readwrite, readonly)</a> </dt>
</p></div>
<p style="text-align: center;"> <strong>iPhone开发之深入浅出 (2) &mdash; ARC之@property使用</strong> </p>
<p>上一回我们学到了一些ARC的基本概念，这一次我们来看看ARC对@property的使用规则有何影响。</p>
<h4></span><a name="sec1" id="sec1"></a>所有者属性</h4>
<p class="first">我们先来看看与所有权有关系的属性，关键字间的对应关系。</p>
<table class="muse-table" border="2" cellpadding="5">
<thead>
<tr>
<th>属性值</th>
<th>关键字</th>
<th>所有权</th>
</tr>
</thead>
<tbody>
<tr>
<td>strong</td>
<td>__strong</td>
<td>有</td>
</tr>
<tr>
<td>weak</td>
<td>__weak</td>
<td>无</td>
</tr>
<tr>
<td>unsafe_unretained</td>
<td>__unsafe_unretained</td>
<td>无</td>
</tr>
<tr>
<td>copy</td>
<td>__strong</td>
<td>有</td>
</tr>
<tr>
<td>assign</td>
<td>__unsafe_unretained</td>
<td>无</td>
</tr>
<tr>
<td>retain</td>
<td>__strong</td>
<td>有</td>
</tr>
</tbody>
</table>
<dl>
<dt><strong>strong</strong></dt>
<dd>
<p>该属性值对应 __strong 关键字，即该属性所声明的变量将成为对象的持有者。</p>
</dd>
<dt><strong>weak</strong></dt>
<dd>
<p>该属性对应 __weak 关键字，与 __weak 定义的变量一致，该属性所声明的变量将没有对象的所有权，并且当对象被破弃之后，对象将被自动赋值nil。</p>
<p>并且，delegate 和 Outlet 应该用 weak 属性来声明。同时，如上一回介绍的 iOS 5 之前的版本是没有 __weak 关键字的，所以 weak 属性是不能使用的。这种情况我们使用 unsafe_unretained。</p>
</dd>
<dt><strong>unsafe_unretained</strong></dt>
<dd>
<p>等效于__unsafe_unretaind关键字声明的变量；像上面说明的，iOS 5之前的系统用该属性代替 weak 来使用。</p>
</dd>
<dt><strong>copy</strong></dt>
<dd>
<p>与 strong 的区别是声明变量是拷贝对象的持有者。</p>
</dd>
<dt><strong>assign</strong></dt>
<dd>
<p>一般Scalar Varible用该属性声明，比如,int, BOOL。</p>
</dd>
<dt><strong>retain</strong></dt>
<dd>
<p>该属性与 strong 一致；只是可读性更强一些。</p>
</dd>
</dl>
<h4></span><a name="sec2" id="sec2"></a>读写相关的属性 (readwrite, readonly)</h4>
<p class="first">读写相关的属性有 readwrite 和 readonly 两种，如果使用ARC之后，我么需要注意一下 readonly 属性的使用。</p>
<p>比如下面的变量声明。</p>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;">@property (nonatomic, readonly) <span class="type">NSString</span> *<span class="variable-name">name</span>;
</pre>
</td>
<tr></table>
</div>
<p>一般声明为 readonly 的变量按理说应该不需要持有所有权了，但是在ARC有效的情况下，将出现下面的错误信息 ：</p>
<blockquote>
<p class="quoted">“ARC forbids synthesizing a property of an Objective-C object with unspecified ownership or storage attribute”</p>
</blockquote>
<p><strong>如果定义了ARC有效，那么必须要有所有者属性的定义</strong>；所以我们的代码改成这样，就OK了</p>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;">@property (nonatomic, strong, readonly) <span class="type">NSString</span> *<span class="variable-name">name</span>;
</pre>
</td>
<tr></table>
</div>
<p>不过有一点，Scalar Varible的变量缺省都有 assign 的属性定义，所以不需要给他们单独的明示声明了。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.yifeiyang.net/development-of-the-iphone-simply-2/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>iPhone开发之深入浅出 (1) &#8212; ARC是什么</title>
		<link>http://www.yifeiyang.net/development-of-the-iphone-simply-1/</link>
		<comments>http://www.yifeiyang.net/development-of-the-iphone-simply-1/#comments</comments>
		<pubDate>Sun, 01 Jan 2012 01:04:00 +0000</pubDate>
		<dc:creator>yang</dc:creator>
				<category><![CDATA[ARC]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[深入浅出]]></category>
		<category><![CDATA[Objective-C]]></category>

		<guid isPermaLink="false">http://www.yifeiyang.net/iphone%e5%bc%80%e5%8f%91%e4%b9%8b%e6%b7%b1%e5%85%a5%e6%b5%85%e5%87%ba-1-arc%e6%98%af%e4%bb%80%e4%b9%88/</guid>
		<description><![CDATA[<div class="contents"> <dt> <a href="#sec1">ARC是什么</a> </dt> <dd> <dl> <dt> <a href="#sec2">变化点</a> </dt> <dt> <a href="#sec3">使用ARC的好处</a> </dt> <dt> <a href="#sec4">不好的地方</a> </dt> </dl> </dd> <dt> <a href="#sec5">ARC基本规则</a> </dt> <dd> <dl> <dt> <a href="#sec6">Objective-C对象</a> </dt> <dt> <a href="#sec7">引用关键字</a> </dt> </dl> </dd> <dt> <a href="#sec8">总结</a> </dt> </div>    <p style="text-align: center;"> <strong>iPhone开发之深入浅出 (1) &#8212; ARC是什么</strong> </p>  <p>新年伊始，万象更新。新一年开始，我们来更加深入了解一下iPhone开发的内部。作为开始，我们先来了解一下ARC。</p>  <h3><a name="sec1" id="sec1"></a>ARC是什么</h3>  <p class="first">ARC是iOS 5推出的新功能，全称叫 ARC(Automatic Reference Counting)。简单地说，就是代码中自动加入了retain/release，原先需要手动添加的用来处理内存管理的引用计数的代码可以自动地由编译器完成了。</p>  <p>该机能在 iOS 5/ Mac OS X 10.7 开始导入，利用 Xcode4.2 可以使用该机能。简单地理解ARC，就是通过指定的语法，让编译器(LLVM 3.0)在编译代码时，自动生成实例的引用计数管理部分代码。有一点，ARC并不是GC，它只是一种代码静态分析（Static Analyzer）工具。</p>  <h4><a name="sec2" id="sec2"></a>变化点</h4>  <p class="first">通过一小段代码，我们看看使用ARC前后的变化点。</p>  <div class="codebox"> <table width="100%"> <tr> <td class="line_numbers"> <pre>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre></td><td>
<pre class="src" style="color:#f5deb3;"><span class="keyword">@interface</span> <span class="type">NonARCObject</span> : <span class="type">NSObject</span> {
    <span class="type">NSString</span> *<span class="variable-name">name</span>;
}
-(<span class="type">id</span>)<span class="function-name">initWithName</span>:(<span class="type">NSString</span> *)<span class="variable-name">name</span>;
<span class="keyword">@end</span>

<span class="keyword">@implementation</span> <span class="type">NonARCObject</span>
-(<span class="type">id</span>)<span class="function-name">initWithName</span>:(<span class="type">NSString</span> *)<span class="variable-name">newName</span> {
    <span class="keyword">self</span> = [<span class="keyword">super</span> init];
    <span class="keyword">if</span> (<span class="keyword">self</span>) {
        name = [newName retain];
    }
    <span class="keyword">return</span> <span class="keyword">self</span>;
}

-(<span class="type">void</span>)<span class="function-name">dealloc</span> {
    [name release];
    [<span class="type">Super</span> dealloc];
}
<span class="keyword">@end</span>
</pre></td><tr></table></div>


<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td>
<pre class="src" style="color:#f5deb3;"><span class="keyword">@interface</span> <span class="type">ARCObject</span> : <span class="type">NSObject</span> {
    <span class="type">NSString</span> *<span class="variable-name">name</span>;
}
-(<span class="type">id</span>)<span class="function-name">initWithName</span>:(<span class="type">NSString</span> *)<span class="variable-name">name</span>;
<span class="keyword">@end</span>

<span class="keyword">@implementation</span> <span class="type">ARCObject</span>
-(<span class="type">id</span>)<span class="function-name">initWithName</span>:(<span class="type">NSString</span> *)<span class="variable-name">newName</span> {
    <span class="keyword">self</span> = [<span class="keyword">super</span> init];
    <span class="keyword">if</span> (<span class="keyword">self</span>) {
        name = newName;
    }
    <span class="keyword">return</span> <span class="keyword">self</span>;
}
<span class="keyword">@end</span>
</pre></td><tr></table></div>


<dl>
<dt><strong>我们之前使用Objective-C中内存管理规则时，往往采用下面的准则</strong></dt><dd></dd>
</dl>

<ul>
<li>生成对象时，使用autorelease</li>
<li>对象代入时，先autorelease后再retain</li>
<li>对象在函数中返回时，使用return [[object retain] autorelease];</li>
</ul>

<p>而使用ARC后，我们可以不需要这样做了，甚至连最基础的release都不需要了。</p>


<h4><a name="sec3" id="sec3"></a>使用ARC的好处</h4>

<p class="first">使用ARC有什么好处呢？</p>

<ul>
<li>看到上面的例子，大家就知道了，以后写Objective-C的代码变得简单多了，因为我们不需要担心烦人的内存管理，担心内存泄露了</li>
<li>代码的总量变少了，看上去清爽了不少，也节省了劳动力</li>
<li>代码高速化，由于使用编译器管理引用计数，减少了低效代码的可能性</li>
</ul>


<h4><a name="sec4" id="sec4"></a>不好的地方</h4>

<ul>
<li>记住一堆新的ARC规则 &#8212; 关键字及特性等需要一定的学习周期</li>
<li>一些旧的代码，第三方代码使用的时候比较麻烦；修改代码需要工数，要么修改编译开关</li>
</ul>

<p>关于第二点，由于 XCode4.2 中缺省ARC就是 ON 的状态，所以编译旧代码的时候往往有&#34;Automatic Reference Counting Issue&#34;的错误信息。</p>

<div class="imagebox">
<p><a href="http://www.yifeiyang.net/images/iphone/ARC/error.png">
<img src="http://www.yifeiyang.net/images/iphone/ARC/error.png" alt="ARC_error" /></a>
</p></div>

<p>这个时候，可以将项目编译设置中的“Objectice-C Auto Reference Counteting”设为NO。如下所示。</p>


<div class="imagebox">
<p><a href="http://www.yifeiyang.net/images/iphone/ARC/ARC_Xcode1.png">
<img src="http://www.yifeiyang.net/images/iphone/ARC/ARC_Xcode1.png" alt="ARC_Xcode" /></a>
</p></div>


<p>如果只想对某个.m文件不适应ARC，可以只针对该类文件加上 -fno-objc-arc 编译FLAGS，如下图。</p>


<div class="imagebox">
<p><a href="http://www.yifeiyang.net/images/iphone/ARC/ARC_Xcode2.png">
<img src="http://www.yifeiyang.net/images/iphone/ARC/ARC_Xcode2.png" alt="ARC_Xcode" /></a>
</p></div>



<h3><a name="sec5" id="sec5"></a>ARC基本规则</h3>

<ul>
<li>retain, release, autorelease, dealloc由编译器自动插入，不能在代码中调用</li>
<li>dealloc虽然可以被重载，但是不能调用[super dealloc]</li>
</ul>

<p>由于ARC并不是GC，并需要一些规则让编译器支持代码插入，所以必须清楚清楚了这些规则后，才能写出健壮的代码。</p>


<h4><a name="sec6" id="sec6"></a>Objective-C对象</h4>

<p class="first">ObjectiveC中的对象，有强参照(Strong reference)和弱参照(Weak reference)之分，当需要保持其他对象的时候，需要retain以确保对象引用计数加1。对象的持有者(owner)只要存在，那么该对象的强参照就一直存在。</p>

<dl>
<dt><strong>对象处理的基本规则是</strong></dt><dd></dd>
</dl>

<ul>
<li>只要对象的持有者存在（对象被强参照），那么就可以使用该对象</li>
<li>对象失去了持有者后，即被破弃</li>
</ul>

<h5>强参照 (Strong reference)</h5>

<div class="imagebox">
<p><a href="http://www.yifeiyang.net/images/iphone/ARC/ARC_outline_strong.JPG">
<img src="http://www.yifeiyang.net/images/iphone/ARC/ARC_outline_strong.JPG" alt="ARC_outline_strong" /></a>
</p></div>


<dl>
<dt><strong>(s1)</strong></dt><dd></dd>
</dl>

<p>firstName作为”natsu”字符串对象的最初持有者，是该NSString类型对象的Strong reference。</p>


<dl>
<dt><strong>(s2)</strong></dt><dd></dd>
</dl>

<p>这里将firstName代入到aName中，即aName也成为了@”natsu”字符串对象的持有者，对于该对象，aName也是Strong reference。</p>


<dl>
<dt><strong>(s3)</strong></dt><dd></dd>
</dl>

<p>这里，改变firstName的内容。生成新的字符串对象”maki”。这时候firstName成为”maki”的持有者，而@”natsu”的持有者只有aName。每个字符串对象都有各自的持有者，所以它们都在内存中都存在。</p>

<dl>
<dt><strong>(s4)</strong></dt><dd></dd>
</dl>

<p>追加新的变量otherName, 它将成为@”maki”对象的另一个持有者。即NSString类型对象的Strong reference。</p>

<dl>
<dt><strong>(s5)</strong></dt><dd></dd>
</dl>

<p>将otherName代入到aName，这时，aName将成为@”maki”字符串对象的持有者。而对象@”natsu”已经没有持有者了，该对象将被破弃。</p>


<h5>弱参照 (Weak reference)</h5>

<p>接下来我们来看看弱参照 (Weak reference) 的使用方式。</p>

<div class="imagebox">
<p><a href="http://www.yifeiyang.net/images/iphone/ARC/ARC_outline_weak.png">
<img src="http://www.yifeiyang.net/images/iphone/ARC/ARC_outline_weak.png" alt="ARC_outline_weak" /></a>
</p></div>

<dl>
<dt><strong>(w1)</strong></dt><dd></dd>
</dl>

<p>与强参照方式同样，firstName作为字符串对象@”natsu”的持有者存在。即是该NSString类型对象的Strong reference。</p>

<dl>
<dt><strong>(w2)</strong></dt><dd></dd>
</dl>

<p>使用关键字__weak，声明弱参照weakName变量，将firstName代入。这时weakName虽然参照@”natsu”，但仍是Weak reference。即weakName虽然能看到@”natsu”，但不是其持有者。</p>

<dl>
<dt><strong>(w3)</strong></dt><dd></dd>
</dl>

<p>firstName指向了新的对象@”maki”，成为其持有者，而对象@”natsu”因为没有了持有者，即被破弃。同时weakName变量将被自动代入nil。</p>



<h4><a name="sec7" id="sec7"></a>引用关键字</h4>

<p class="first">ARC中关于对象的引用参照，主要有下面几关键字。使用strong, weak, autoreleasing限定的变量会被隐式初始化为nil。</p>

<dl>
<dt><strong>__strong</strong></dt><dd></dd>
</dl>

<p>变量声明缺省都带有__strong关键字，如果变量什么关键字都不写，那么缺省就是强参照。</p>

<dl>
<dt><strong>__weak</strong></dt><dd></dd>
</dl>

<p>上面已经看到了，这是弱参照的关键字。该概念是新特性，从 iOS 5/ Mac OS X 10.7 开始导入。由于该类型不影响对象的生命周期，所以如果对象之前就没有持有者，那么会出现刚创建就被破弃的问题，比如下面的代码。</p>

<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
</pre></td><td>
<pre class="src" style="color:#f5deb3;">NSString __weak *string = [[<span class="type">NSString</span> alloc] initWithFormat:@<span class="string">"First Name: %@"</span>, [<span class="keyword">self</span> firstName]];
NSLog(@<span class="string">"string: %@"</span>, string); <span class="comment-delimiter">//</span><span class="comment">&#27492;&#26102; string&#20026;&#31354;
</span></pre></td><tr></table></div>


<p>如果编译设定OS版本 Deployment Target 设定为这比这低的版本，那么编译时将报错(The current deployment target does not support automated __weak references)，这个时候，我们可以使用下面的__unsafe_unretained。</p>

<p>弱参照还有一个特征，即当参数对象失去所有者之后，变量会被自动付上nil (Zeroing)。</p>

<dl>
<dt><strong>__unsafe_unretained</strong></dt><dd></dd>
</dl>

<p>该关键字与__weak一样，也是弱参照，与__weak的区别只是是否执行nil赋值(Zeroing)。但是这样，需要注意变量所指的对象已经被破弃了，地址还还存在，但内存中对象已经没有了。如果还是访问该对象，将引起「BAD_ACCESS」错误。</p>

<dl>
<dt><strong>__autoreleasing</strong></dt><dd></dd>
</dl>

<p>该关键字使对像延迟释放。比如你想传一个未初始化的对像引用到一个方法当中，在此方法中实例化此对像，那么这种情况可以使用__autoreleasing。他被经常用于函数有值参数返回时的处理，比如下面的例子。</p>

<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
9
10
11
</pre></td><td>
<pre class="src" style="color:#f5deb3;">- (<span class="type">void</span>) <span class="function-name">generateErrorInVariable</span>:(__autoreleasing NSError **)<span class="variable-name">paramError</span> {
    ....
    *paramError = [[<span class="type">NSError</span> alloc] initWithDomain:@<span class="string">"MyApp"</span> code:1 userInfo:errorDictionary];
}

....
{
    <span class="type">NSError</span> *<span class="variable-name">error</span> = <span class="constant">nil</span>;
    [<span class="keyword">self</span> generateErrorInVariable:&#38;error];
    NSLog(@<span class="string">"Error = %@"</span>, error);
}
</pre></td><tr></table></div>


<p>又如函数的返回值是在函数中申请的，那么希望释放是在调用端时，往往有下面的代码。</p>

<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td>
<pre class="src" style="color:#f5deb3;">-(<span class="type">NSString</span> *)<span class="function-name">stringTest</span>
{
    <span class="type">NSString</span> *<span class="variable-name">retStr</span> = [<span class="type">NSString</span> stringWithString:@<span class="string">"test"</span>];

    <span class="keyword">return</span> [[retStr retain] autorelease];
}

<span class="comment-delimiter">// </span><span class="comment">&#20351;&#29992;ARC
</span>
-(<span class="type">NSString</span> *)<span class="function-name">stringTest</span>
{
    __autoreleasing NSString *retStr = [<span class="type">NSString</span> alloc] initWithString:@<span class="string">"test"</span>];

    <span class="keyword">return</span> retStr;
}
</pre></td><tr></table></div>


<p>即当方法的参数是id*，且希望方法返回时对象被autoreleased，那么使用该关键字。</p>




<h3><a name="sec8" id="sec8"></a>总结</h3>

<dl>
<dt><strong>今天，我们看到了基本的ARC使用规则</strong></dt><dd></dd>
</dl>

<ul>
<li>代码中不能使用retain, release, retain, autorelease</li>
<li>不重载dealloc（如果是释放对象内存以外的处理，是可以重载该函数的，但是不能调用[super dealloc]）</li>
<li>不能使用NSAllocateObject, NSDeallocateObject</li>
<li>不能在C结构体中使用对象指针</li>
<li>id与void *间的如果cast时需要用特定的方法（__bridge关键字）</li>
<li>不能使用NSAutoReleasePool、而需要@autoreleasepool块</li>
<li>不能使用“new”开始的属性名称 （如果使用会有下面的编译错误”Property’s synthesized getter follows Cocoa naming convention for returning ‘owned’ objects”）</li>
</ul>

<p>今后，我们将更加深入ARC，学习其更多的特性。</p>]]></description>
			<content:encoded><![CDATA[<div class="contents">
<dt> <a href="#sec1">ARC是什么</a> </dt>
<dd>
<dl>
<dt> <a href="#sec2">变化点</a> </dt>
<dt> <a href="#sec3">使用ARC的好处</a> </dt>
<dt> <a href="#sec4">不好的地方</a> </dt>
</dl>
</dd>
<dt> <a href="#sec5">ARC基本规则</a> </dt>
<dd>
<dl>
<dt> <a href="#sec6">Objective-C对象</a> </dt>
<dt> <a href="#sec7">引用关键字</a> </dt>
</dl>
</dd>
<dt> <a href="#sec8">总结</a> </dt>
</p></div>
<p style="text-align: center;"> <strong>iPhone开发之深入浅出 (1) &mdash; ARC是什么</strong> </p>
<p>新年伊始，万象更新。新一年开始，我们来更加深入了解一下iPhone开发的内部。作为开始，我们先来了解一下ARC。</p>
<h3><a name="sec1" id="sec1"></a>ARC是什么</h3>
<p class="first">ARC是iOS 5推出的新功能，全称叫 ARC(Automatic Reference Counting)。简单地说，就是代码中自动加入了retain/release，原先需要手动添加的用来处理内存管理的引用计数的代码可以自动地由编译器完成了。</p>
<p>该机能在 iOS 5/ Mac OS X 10.7 开始导入，利用 Xcode4.2 可以使用该机能。简单地理解ARC，就是通过指定的语法，让编译器(LLVM 3.0)在编译代码时，自动生成实例的引用计数管理部分代码。有一点，ARC并不是GC，它只是一种代码静态分析（Static Analyzer）工具。</p>
<h4><a name="sec2" id="sec2"></a>变化点</h4>
<p class="first">通过一小段代码，我们看看使用ARC前后的变化点。</p>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;"><span class="keyword">@interface</span> <span class="type">NonARCObject</span> : <span class="type">NSObject</span> {
    <span class="type">NSString</span> *<span class="variable-name">name</span>;
}
-(<span class="type">id</span>)<span class="function-name">initWithName</span>:(<span class="type">NSString</span> *)<span class="variable-name">name</span>;
<span class="keyword">@end</span>

<span class="keyword">@implementation</span> <span class="type">NonARCObject</span>
-(<span class="type">id</span>)<span class="function-name">initWithName</span>:(<span class="type">NSString</span> *)<span class="variable-name">newName</span> {
    <span class="keyword">self</span> = [<span class="keyword">super</span> init];
    <span class="keyword">if</span> (<span class="keyword">self</span>) {
        name = [newName retain];
    }
    <span class="keyword">return</span> <span class="keyword">self</span>;
}

-(<span class="type">void</span>)<span class="function-name">dealloc</span> {
    [name release];
    [<span class="type">Super</span> dealloc];
}
<span class="keyword">@end</span>
</pre>
</td>
<tr></table>
</div>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;"><span class="keyword">@interface</span> <span class="type">ARCObject</span> : <span class="type">NSObject</span> {
    <span class="type">NSString</span> *<span class="variable-name">name</span>;
}
-(<span class="type">id</span>)<span class="function-name">initWithName</span>:(<span class="type">NSString</span> *)<span class="variable-name">name</span>;
<span class="keyword">@end</span>

<span class="keyword">@implementation</span> <span class="type">ARCObject</span>
-(<span class="type">id</span>)<span class="function-name">initWithName</span>:(<span class="type">NSString</span> *)<span class="variable-name">newName</span> {
    <span class="keyword">self</span> = [<span class="keyword">super</span> init];
    <span class="keyword">if</span> (<span class="keyword">self</span>) {
        name = newName;
    }
    <span class="keyword">return</span> <span class="keyword">self</span>;
}
<span class="keyword">@end</span>
</pre>
</td>
<tr></table>
</div>
<dl>
<dt><strong>我们之前使用Objective-C中内存管理规则时，往往采用下面的准则</strong></dt>
<dd></dd>
</dl>
<ul>
<li>生成对象时，使用autorelease</li>
<li>对象代入时，先autorelease后再retain</li>
<li>对象在函数中返回时，使用return [[object retain] autorelease];</li>
</ul>
<p>而使用ARC后，我们可以不需要这样做了，甚至连最基础的release都不需要了。</p>
<h4><a name="sec3" id="sec3"></a>使用ARC的好处</h4>
<p class="first">使用ARC有什么好处呢？</p>
<ul>
<li>看到上面的例子，大家就知道了，以后写Objective-C的代码变得简单多了，因为我们不需要担心烦人的内存管理，担心内存泄露了</li>
<li>代码的总量变少了，看上去清爽了不少，也节省了劳动力</li>
<li>代码高速化，由于使用编译器管理引用计数，减少了低效代码的可能性</li>
</ul>
<h4><a name="sec4" id="sec4"></a>不好的地方</h4>
<ul>
<li>记住一堆新的ARC规则 &mdash; 关键字及特性等需要一定的学习周期</li>
<li>一些旧的代码，第三方代码使用的时候比较麻烦；修改代码需要工数，要么修改编译开关</li>
</ul>
<p>关于第二点，由于 XCode4.2 中缺省ARC就是 ON 的状态，所以编译旧代码的时候往往有&quot;Automatic Reference Counting Issue&quot;的错误信息。</p>
<div class="imagebox">
<p><a href="http://www.yifeiyang.net/images/iphone/ARC/error.png" rel="lightbox[442]"><br />
<img src="http://www.yifeiyang.net/images/iphone/ARC/error.png" alt="ARC_error" /></a>
</p>
</div>
<p>这个时候，可以将项目编译设置中的“Objectice-C Auto Reference Counteting”设为NO。如下所示。</p>
<div class="imagebox">
<p><a href="http://www.yifeiyang.net/images/iphone/ARC/ARC_Xcode1.png" rel="lightbox[442]"><br />
<img src="http://www.yifeiyang.net/images/iphone/ARC/ARC_Xcode1.png" alt="ARC_Xcode" /></a>
</p>
</div>
<p>如果只想对某个.m文件不适应ARC，可以只针对该类文件加上 -fno-objc-arc 编译FLAGS，如下图。</p>
<div class="imagebox">
<p><a href="http://www.yifeiyang.net/images/iphone/ARC/ARC_Xcode2.png" rel="lightbox[442]"><br />
<img src="http://www.yifeiyang.net/images/iphone/ARC/ARC_Xcode2.png" alt="ARC_Xcode" /></a>
</p>
</div>
<h3><a name="sec5" id="sec5"></a>ARC基本规则</h3>
<ul>
<li>retain, release, autorelease, dealloc由编译器自动插入，不能在代码中调用</li>
<li>dealloc虽然可以被重载，但是不能调用[super dealloc]</li>
</ul>
<p>由于ARC并不是GC，并需要一些规则让编译器支持代码插入，所以必须清楚清楚了这些规则后，才能写出健壮的代码。</p>
<h4><a name="sec6" id="sec6"></a>Objective-C对象</h4>
<p class="first">ObjectiveC中的对象，有强参照(Strong reference)和弱参照(Weak reference)之分，当需要保持其他对象的时候，需要retain以确保对象引用计数加1。对象的持有者(owner)只要存在，那么该对象的强参照就一直存在。</p>
<dl>
<dt><strong>对象处理的基本规则是</strong></dt>
<dd></dd>
</dl>
<ul>
<li>只要对象的持有者存在（对象被强参照），那么就可以使用该对象</li>
<li>对象失去了持有者后，即被破弃</li>
</ul>
<h5>强参照 (Strong reference)</h5>
<div class="imagebox">
<p><a href="http://www.yifeiyang.net/images/iphone/ARC/ARC_outline_strong.JPG" rel="lightbox[442]"><br />
<img src="http://www.yifeiyang.net/images/iphone/ARC/ARC_outline_strong.JPG" alt="ARC_outline_strong" /></a>
</p>
</div>
<dl>
<dt><strong>(s1)</strong></dt>
<dd></dd>
</dl>
<p>firstName作为”natsu”字符串对象的最初持有者，是该NSString类型对象的Strong reference。</p>
<dl>
<dt><strong>(s2)</strong></dt>
<dd></dd>
</dl>
<p>这里将firstName代入到aName中，即aName也成为了@”natsu”字符串对象的持有者，对于该对象，aName也是Strong reference。</p>
<dl>
<dt><strong>(s3)</strong></dt>
<dd></dd>
</dl>
<p>这里，改变firstName的内容。生成新的字符串对象”maki”。这时候firstName成为”maki”的持有者，而@”natsu”的持有者只有aName。每个字符串对象都有各自的持有者，所以它们都在内存中都存在。</p>
<dl>
<dt><strong>(s4)</strong></dt>
<dd></dd>
</dl>
<p>追加新的变量otherName, 它将成为@”maki”对象的另一个持有者。即NSString类型对象的Strong reference。</p>
<dl>
<dt><strong>(s5)</strong></dt>
<dd></dd>
</dl>
<p>将otherName代入到aName，这时，aName将成为@”maki”字符串对象的持有者。而对象@”natsu”已经没有持有者了，该对象将被破弃。</p>
<h5>弱参照 (Weak reference)</h5>
<p>接下来我们来看看弱参照 (Weak reference) 的使用方式。</p>
<div class="imagebox">
<p><a href="http://www.yifeiyang.net/images/iphone/ARC/ARC_outline_weak.png" rel="lightbox[442]"><br />
<img src="http://www.yifeiyang.net/images/iphone/ARC/ARC_outline_weak.png" alt="ARC_outline_weak" /></a>
</p>
</div>
<dl>
<dt><strong>(w1)</strong></dt>
<dd></dd>
</dl>
<p>与强参照方式同样，firstName作为字符串对象@”natsu”的持有者存在。即是该NSString类型对象的Strong reference。</p>
<dl>
<dt><strong>(w2)</strong></dt>
<dd></dd>
</dl>
<p>使用关键字__weak，声明弱参照weakName变量，将firstName代入。这时weakName虽然参照@”natsu”，但仍是Weak reference。即weakName虽然能看到@”natsu”，但不是其持有者。</p>
<dl>
<dt><strong>(w3)</strong></dt>
<dd></dd>
</dl>
<p>firstName指向了新的对象@”maki”，成为其持有者，而对象@”natsu”因为没有了持有者，即被破弃。同时weakName变量将被自动代入nil。</p>
<h4><a name="sec7" id="sec7"></a>引用关键字</h4>
<p class="first">ARC中关于对象的引用参照，主要有下面几关键字。使用strong, weak, autoreleasing限定的变量会被隐式初始化为nil。</p>
<dl>
<dt><strong>__strong</strong></dt>
<dd></dd>
</dl>
<p>变量声明缺省都带有__strong关键字，如果变量什么关键字都不写，那么缺省就是强参照。</p>
<dl>
<dt><strong>__weak</strong></dt>
<dd></dd>
</dl>
<p>上面已经看到了，这是弱参照的关键字。该概念是新特性，从 iOS 5/ Mac OS X 10.7 开始导入。由于该类型不影响对象的生命周期，所以如果对象之前就没有持有者，那么会出现刚创建就被破弃的问题，比如下面的代码。</p>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;">NSString __weak *string = [[<span class="type">NSString</span> alloc] initWithFormat:@<span class="string">"First Name: %@"</span>, [<span class="keyword">self</span> firstName]];
NSLog(@<span class="string">"string: %@"</span>, string); <span class="comment-delimiter">//</span><span class="comment">&#27492;&#26102; string&#20026;&#31354;
</span></pre>
</td>
<tr></table>
</div>
<p>如果编译设定OS版本 Deployment Target 设定为这比这低的版本，那么编译时将报错(The current deployment target does not support automated __weak references)，这个时候，我们可以使用下面的__unsafe_unretained。</p>
<p>弱参照还有一个特征，即当参数对象失去所有者之后，变量会被自动付上nil (Zeroing)。</p>
<dl>
<dt><strong>__unsafe_unretained</strong></dt>
<dd></dd>
</dl>
<p>该关键字与__weak一样，也是弱参照，与__weak的区别只是是否执行nil赋值(Zeroing)。但是这样，需要注意变量所指的对象已经被破弃了，地址还还存在，但内存中对象已经没有了。如果还是访问该对象，将引起「BAD_ACCESS」错误。</p>
<dl>
<dt><strong>__autoreleasing</strong></dt>
<dd></dd>
</dl>
<p>该关键字使对像延迟释放。比如你想传一个未初始化的对像引用到一个方法当中，在此方法中实例化此对像，那么这种情况可以使用__autoreleasing。他被经常用于函数有值参数返回时的处理，比如下面的例子。</p>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
9
10
11
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;">- (<span class="type">void</span>) <span class="function-name">generateErrorInVariable</span>:(__autoreleasing NSError **)<span class="variable-name">paramError</span> {
    ....
    *paramError = [[<span class="type">NSError</span> alloc] initWithDomain:@<span class="string">"MyApp"</span> code:1 userInfo:errorDictionary];
}

....
{
    <span class="type">NSError</span> *<span class="variable-name">error</span> = <span class="constant">nil</span>;
    [<span class="keyword">self</span> generateErrorInVariable:&amp;error];
    NSLog(@<span class="string">"Error = %@"</span>, error);
}
</pre>
</td>
<tr></table>
</div>
<p>又如函数的返回值是在函数中申请的，那么希望释放是在调用端时，往往有下面的代码。</p>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;">-(<span class="type">NSString</span> *)<span class="function-name">stringTest</span>
{
    <span class="type">NSString</span> *<span class="variable-name">retStr</span> = [<span class="type">NSString</span> stringWithString:@<span class="string">"test"</span>];

    <span class="keyword">return</span> [[retStr retain] autorelease];
}

<span class="comment-delimiter">// </span><span class="comment">&#20351;&#29992;ARC
</span>
-(<span class="type">NSString</span> *)<span class="function-name">stringTest</span>
{
    __autoreleasing NSString *retStr = [<span class="type">NSString</span> alloc] initWithString:@<span class="string">"test"</span>];

    <span class="keyword">return</span> retStr;
}
</pre>
</td>
<tr></table>
</div>
<p>即当方法的参数是id*，且希望方法返回时对象被autoreleased，那么使用该关键字。</p>
<h3><a name="sec8" id="sec8"></a>总结</h3>
<dl>
<dt><strong>今天，我们看到了基本的ARC使用规则</strong></dt>
<dd></dd>
</dl>
<ul>
<li>代码中不能使用retain, release, retain, autorelease</li>
<li>不重载dealloc（如果是释放对象内存以外的处理，是可以重载该函数的，但是不能调用[super dealloc]）</li>
<li>不能使用NSAllocateObject, NSDeallocateObject</li>
<li>不能在C结构体中使用对象指针</li>
<li>id与void *间的如果cast时需要用特定的方法（__bridge关键字）</li>
<li>不能使用NSAutoReleasePool、而需要@autoreleasepool块</li>
<li>不能使用“new”开始的属性名称 （如果使用会有下面的编译错误”Property’s synthesized getter follows Cocoa naming convention for returning ‘owned’ objects”）</li>
</ul>
<p>今后，我们将更加深入ARC，学习其更多的特性。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.yifeiyang.net/development-of-the-iphone-simply-1/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>iPhone开发技巧之发布篇（6）&#8212;   不需Developper认证的真机调试方法</title>
		<link>http://www.yifeiyang.net/iphone-release-of-developing-skills-paper-6/</link>
		<comments>http://www.yifeiyang.net/iphone-release-of-developing-skills-paper-6/#comments</comments>
		<pubDate>Sun, 25 Dec 2011 00:05:00 +0000</pubDate>
		<dc:creator>yang</dc:creator>
				<category><![CDATA[发布篇]]></category>
		<category><![CDATA[开发技巧]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[linux]]></category>

		<guid isPermaLink="false">http://www.yifeiyang.net/iphone%e5%bc%80%e5%8f%91%e6%8a%80%e5%b7%a7%e4%b9%8b%e5%8f%91%e5%b8%83%e7%af%87%ef%bc%886%ef%bc%89-%e4%b8%8d%e9%9c%80developper%e8%ae%a4%e8%af%81%e7%9a%84%e7%9c%9f%e6%9c%ba%e8%b0%83%e8%af%95/</guid>
		<description><![CDATA[<div class="contents"> <dt> <a href="#sec1">制作证明书</a> </dt> <dt> <a href="#sec2">程序设置</a> </dt> <dt> <a href="#sec3">署名</a> </dt> <dt> <a href="#sec4">验证</a> </dt> </div>   <p style="text-align: center;"> <strong>iPhone开发技巧之发布篇（6）&#8212; 不需Developper认证的真机调试方法</strong> </p>  <p>以前，<a href="http://www.yifeiyang.net/introduction-to-iphone-development-10-devices-running-the-program/">iPhone开发入门（10）--- 设备上运行程序</a>中介绍了正式注册iPhone/iOS Developer Program后在设备运行程序的方法；在<a href="http://www.yifeiyang.net/iphone-development-introduction-3-linux-development-environment-on-the-build-iphone-os3-1-2/">iPhone开发入门（3）—Linux上构筑iPhone OS3.1.2开发环境</a> 和 <a href="http://www.yifeiyang.net/iphone-development-advanced-4-use-the-makefile-to-compile-iphone-program-automatically/">iPhone开发进阶（4） --- 使用Makefile自动编译iPhone程序</a> 也简单介绍了在越狱机器上运行程序的方法。</p>  <p>今天给大家介绍另一种不需要注册iPhone/iOS Developer Program，也可以简单地在设备中运行程序的方法.</p>  <h3><a name="sec1" id="sec1"></a>制作证明书</h3>  <dl> <dt><strong>首先通过Keychain制作一个新的证明书 Keychain Access -&#62; Certificate Assistant -&#62; Create a Certification</strong></dt><dd></dd> </dl>  <div class="imagebox"> <p><a href="http://www.yifeiyang.net/images/iphone/developper/1.png"> <img src="http://www.yifeiyang.net/images/iphone/developper/1.png" alt="1" /></a> </p></div>   <p>证明书的名称任意(需要记住，下面会用到)，固有类型选择self-signed root，证明书类型选择Code Signing，并选择“let me override defaults”。</p>  <div class="imagebox"> <p><a href="http://www.yifeiyang.net/images/iphone/developper/2.png"> <img src="http://www.yifeiyang.net/images/iphone/developper/2.png" alt="2" /></a> </p></div>   <h3><a name="sec2" id="sec2"></a>程序设置</h3>  <p class="first">程序的Code Signing都设置为「Don’t Code Sign」</p>  <div class="imagebox"> <p><a href="http://www.yifeiyang.net/images/iphone/developper/6.png"> <img src="http://www.yifeiyang.net/images/iphone/developper/6.png" alt="6" /></a> </p></div>  <dl> <dt><strong>编辑SDKSettings.plist文件</strong></dt><dd>  <p>/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/SDKSettings.plist</p></dd> </dl>  <p>将 CODE_SIGNING_REQUIRED 设置为 NO。</p>  <div class="imagebox"> <p><a href="http://www.yifeiyang.net/images/iphone/developper/8.png"> <img src="http://www.yifeiyang.net/images/iphone/developper/8.png" alt="8" /></a> </p></div>  <p>设置之后编译程序 for iOS Device。</p>   <h3><a name="sec3" id="sec3"></a>署名</h3>  <dl> <dt><strong>在控制台用codesign给应用程序署名</strong></dt><dd></dd> </dl>  <div class="codebox"> <table width="100%"> <tr> <td class="line_numbers"> <pre>
1
</pre></td><td>
<pre class="src" style="color:#f5deb3;">codesign &#8211;fs &#8220;Fake Code Sign&#8221; ./Application.app/Application
</pre></td><tr></table></div>



<h3><a name="sec4" id="sec4"></a>验证</h3>

<p class="first">制作好Application.app之后，通过iPhoneExplorer，iFile等上传到iPhone的/Applications目录下。并添加执行属性。</p>

<div class="imagebox">
<p><a href="http://www.yifeiyang.net/images/iphone/developper/17.png">
<img src="http://www.yifeiyang.net/images/iphone/developper/17.png" alt="17" /></a>
</p></div>

<p>OK, 可以运行一下我们的程序看看了。</p>]]></description>
			<content:encoded><![CDATA[<div class="contents">
<dt> <a href="#sec1">制作证明书</a> </dt>
<dt> <a href="#sec2">程序设置</a> </dt>
<dt> <a href="#sec3">署名</a> </dt>
<dt> <a href="#sec4">验证</a> </dt>
</p></div>
<p style="text-align: center;"> <strong>iPhone开发技巧之发布篇（6）&mdash; 不需Developper认证的真机调试方法</strong> </p>
<p>以前，<a href="http://www.yifeiyang.net/introduction-to-iphone-development-10-devices-running-the-program/">iPhone开发入门（10）--- 设备上运行程序</a>中介绍了正式注册iPhone/iOS Developer Program后在设备运行程序的方法；在<a href="http://www.yifeiyang.net/iphone-development-introduction-3-linux-development-environment-on-the-build-iphone-os3-1-2/">iPhone开发入门（3）—Linux上构筑iPhone OS3.1.2开发环境</a> 和 <a href="http://www.yifeiyang.net/iphone-development-advanced-4-use-the-makefile-to-compile-iphone-program-automatically/">iPhone开发进阶（4） --- 使用Makefile自动编译iPhone程序</a> 也简单介绍了在越狱机器上运行程序的方法。</p>
<p>今天给大家介绍另一种不需要注册iPhone/iOS Developer Program，也可以简单地在设备中运行程序的方法.</p>
<h3><a name="sec1" id="sec1"></a>制作证明书</h3>
<dl>
<dt><strong>首先通过Keychain制作一个新的证明书 Keychain Access -&gt; Certificate Assistant -&gt; Create a Certification</strong></dt>
<dd></dd>
</dl>
<div class="imagebox">
<p><a href="http://www.yifeiyang.net/images/iphone/developper/1.png" rel="lightbox[436]"> <img src="http://www.yifeiyang.net/images/iphone/developper/1.png" alt="1" /></a> </p>
</div>
<p>证明书的名称任意(需要记住，下面会用到)，固有类型选择self-signed root，证明书类型选择Code Signing，并选择“let me override defaults”。</p>
<div class="imagebox">
<p><a href="http://www.yifeiyang.net/images/iphone/developper/2.png" rel="lightbox[436]"> <img src="http://www.yifeiyang.net/images/iphone/developper/2.png" alt="2" /></a> </p>
</div>
<h3><a name="sec2" id="sec2"></a>程序设置</h3>
<p class="first">程序的Code Signing都设置为「Don’t Code Sign」</p>
<div class="imagebox">
<p><a href="http://www.yifeiyang.net/images/iphone/developper/6.png" rel="lightbox[436]"> <img src="http://www.yifeiyang.net/images/iphone/developper/6.png" alt="6" /></a> </p>
</div>
<dl>
<dt><strong>编辑SDKSettings.plist文件</strong></dt>
<dd>
<p>/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk/SDKSettings.plist</p>
</dd>
</dl>
<p>将 CODE_SIGNING_REQUIRED 设置为 NO。</p>
<div class="imagebox">
<p><a href="http://www.yifeiyang.net/images/iphone/developper/8.png" rel="lightbox[436]"> <img src="http://www.yifeiyang.net/images/iphone/developper/8.png" alt="8" /></a> </p>
</div>
<p>设置之后编译程序 for iOS Device。</p>
<h3><a name="sec3" id="sec3"></a>署名</h3>
<dl>
<dt><strong>在控制台用codesign给应用程序署名</strong></dt>
<dd></dd>
</dl>
<div class="codebox">
<table width="100%">
<tr>
<td class="line_numbers">
<pre>
1
</pre>
</td>
<td>
<pre class="src" style="color:#f5deb3;">codesign &#8211;fs &#8220;Fake Code Sign&#8221; ./Application.app/Application
</pre>
</td>
<tr></table>
</div>
<h3><a name="sec4" id="sec4"></a>验证</h3>
<p class="first">制作好Application.app之后，通过iPhoneExplorer，iFile等上传到iPhone的/Applications目录下。并添加执行属性。</p>
<div class="imagebox">
<p><a href="http://www.yifeiyang.net/images/iphone/developper/17.png" rel="lightbox[436]"><br />
<img src="http://www.yifeiyang.net/images/iphone/developper/17.png" alt="17" /></a>
</p>
</div>
<p>OK, 可以运行一下我们的程序看看了。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.yifeiyang.net/iphone-release-of-developing-skills-paper-6/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>

