关于iOS内存管理的规则思考

ijkqtnzjtctc 8年前
   <h2>关于iOS内存管理的规则思考</h2>    <ul>     <li>自己生成的生成的对象,自己持有。</li>     <li>非自己生成的对象,自己也能持有。</li>     <li>不在需要自己持有的对象时释放。</li>     <li>非自己持有的对象无法释放。</li>    </ul>    <pre>  <code class="language-objectivec">注:这里的自己是对象使用的环境,理解为编程人员本身也没有错</code></pre>    <p>对象操作和Objective-C方法对应</p>    <table>     <thead>      <tr>       <th>对象操作</th>       <th>Objectivew-C方法</th>      </tr>     </thead>     <tbody>      <tr>       <td>生成并持有对象</td>       <td>alloc/copy/mutableCopy/new或以此开头的方法</td>      </tr>      <tr>       <td>持有对象</td>       <td>retain</td>      </tr>      <tr>       <td>释放对象</td>       <td>release</td>      </tr>      <tr>       <td>废弃对象</td>       <td>dealloc</td>      </tr>     </tbody>    </table>    <h2>自己生成的对象,自己持有</h2>    <pre>  <code class="language-objectivec">//自己生成并持有对象  id obj1 = [[NSObject alloc] init];    id obj2 = [NSObject new];    id obj3 = [obj2 copy];</code></pre>    <p>copy 方法基于NSCopying方法约定,实现类中的 copyWithZone:</p>    <p>mutableCopy 方法基于NSMutableCopying方法约定,实现类中的 mutableCopyWithZone:</p>    <h2>非自己生成的对象,自己也能持有</h2>    <p>用alloc/new/copy/mutableCopy以外的方法取得的对象,自己不是该对象的持有者。</p>    <pre>  <code class="language-objectivec">//取的非自己生成并持有的对象,  //取得对象的存在,但自己不持有对象。    id obj = [NSMutableArray array];    id obj2 = [NSDictionary dictionary];    //自己持有对象  [obj retain];    [obj2 retain];</code></pre>    <p>注:这里有点不好理解,我们先来看一段代码:</p>    <pre>  <code class="language-objectivec">//取的非自己生成并持有的对象,  //取得对象的存在,但自己不持有对象。    id unretain_obj = [NSMutableArray array];    NSLog(@"unretain_obj retain count = %lu", (unsigned long)[unretain_obj retainCount]);      //调用 release  [unretain_obj release];</code></pre>    <p>上述代码,我们打印结果是:</p>    <p>2016-12-21 15:32:04.485 acm[65216:852108] unretain_obj retain count = 1</p>    <p>随后调用 release 方法会导致程序崩溃!</p>    <p>按照引用计数来说,这时 unretain_obj 是可以被执行一次release方法的。但是为什么我们直接调用会导致程序崩溃。</p>    <p>我们会想最开始提到的四条思想之一:</p>    <p>无法释放非自己持有的对象</p>    <p>这样我们就很好理解了。虽然打印出 unretain_obj 的 retainCount 为 1 但是不能说明是因为它引用了对象。它只是单纯的获取到了对象的存在而已。</p>    <p>那么我们会产生一个问题。那么这个对象是谁在持有??</p>    <p>我们先做一个猜测:</p>    <p>因为 [NSMutableArray array] 是一个工厂方法,在 array 肯定是要生成一个 NSMutableArray 实例对象。这时也必然会有一个指针引用它然后返回这个对象。so。。。</p>    <p>先想到这里,后边我们再去印证</p>    <p>我们再来看一段代码:</p>    <pre>  <code class="language-objectivec">//取的非自己生成并持有的对象,  //取得对象的存在,但自己不持有对象。  id unretain_obj = [NSMutableArray array];    NSLog(@"unretain_obj retain count = %lu", (unsigned long)[unretain_obj retainCount]);    //自己持有对象  [unretain_obj retain];    NSLog(@"unretain_obj retain count = %lu", (unsigned long)[unretain_obj retainCount]);    //释放自己持有的对象  [unretain_obj release];    NSLog(@"unretain_obj retain count = %lu", (unsigned long)[unretain_obj retainCount]);</code></pre>    <p>打印结果</p>    <p>2016-12-21 15:40:20.774 acm[65682:861135] unretain_obj retain count = 1</p>    <p>2016-12-21 15:40:20.774 acm[65682:861135] unretain_obj retain count = 2</p>    <p>2016-12-21 15:40:25.254 acm[65682:861135] unretain_obj retain count = 1</p>    <p>并且程序也不会崩溃。</p>    <p>着也印证了我们上边的想法。</p>    <p>因为通过 retain 方法,非自己生成的对象跟用alloc/new/copy/mutableCopy方法生成并持有的对象一样,成了自己所持有的</p>    <h2>不在需要自己持有的对象时释放</h2>    <p>通过上边的例子我们知道,自己持有的对象在释放时调用release方法,eg:</p>    <pre>  <code class="language-objectivec">//自己生成并持有对象  id release_obj = [[NSObject alloc] init];    //将自己持有的对象释放  [release_obj release];    /*    * 释放对象   * 指向对象的指针依然被保留在变量release_obj 中,你依然可以调用它。   * 但是对象一经释放绝对不可访问,否则会造成程序崩溃。   * 出现EXC_BAD_ACCESS Crash问题   */</code></pre>    <p>我们自己实现一个方法,返回一个方法调用着也可以持有的对象,即alloc的作用</p>    <pre>  <code class="language-objectivec">- (id)allocObject {       //自己生成并持有对象      id obj = [[NSObject alloc] init];      //原封不动的返回一个由alloc方法生成的对象      return obj;  }</code></pre>    <p>注:方法名符合 生成并持有对象 alloc/copy/mutableCopy/new或以此开头的方法 规则</p>    <p>我们自己实现一个方法,返回一个谁也不持有的对象,只是取得对象的存在</p>    <pre>  <code class="language-objectivec">- (id)object {      //自己生成并持有对象      id obj = [[NSObject alloc] init];        //调用autorelease方法 取得对象的存在,但自己不持有对象。      [obj autorelease];        return obj;  }</code></pre>    <p>autorelease 方法可以取得对象的存在,但自己不持有对象。使对象在超出指定的生存范围时能够自动的并正确的释放(调用 release 方法)</p>    <p>autorelease和release方法的区别</p>    <p>autorelease:</p>    <p>release:</p>    <p>autorelease的详细解说我们后边介绍。</p>    <p>我们也可以通过调用 retain 方法来使 autorelease 方法的来的对象自己持有eg:</p>    <pre>  <code class="language-objectivec">//获取对象的存在,自己不持有   id unretain_obj = [NSMutableArray array];     //持有对象  [unretain_obj retain];</code></pre>    <h2>无法释放非自己持有的对象</h2>    <p>自己已经释放了还继续释放</p>    <pre>  <code class="language-objectivec">//自己生成并持有对象      id release_obj = [[NSObject alloc] init];        //将自己持有的对象释放      [release_obj release];        //释放已经释放的对象      [release_obj release];        /*       * 释放对象       * 指向对象的指针依然被保留在变量release_obj 中,你依然可以调用它。       * 但是对象一经释放绝对不可访问,否则会造成程序崩溃。       * 出现EXC_BAD_ACCESS Crash问题       */</code></pre>    <p>只获取了对象的存在,试图释放对象</p>    <pre>  <code class="language-objectivec">//取的非自己生成并持有的对象,      //取得对象的存在,但自己不持有对象。      id unretain_obj = [NSMutableArray array];      //释放自己不持有的对象      [unretain_obj release];</code></pre>    <p>程序崩溃,报EXC_BAD_ACCESS Crash问题</p>    <p> </p>    <p>来自:http://blog.csdn.net/wxs0124/article/details/53787357</p>    <p> </p>