关于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>