iOS开发:ARC下内存回收机制详解,及如何防止内存泄漏

先看这篇文章,通俗易懂:http://blog.csdn.net/hbw1992322/article/details/52121089


首先,如何打开ARC:

build settings -> searching for ARC -> Objective-C Automatic Reference Counting -> YES


下面我们正式开始认识ARC

1. retainable object pointers

本节介绍retainable object pointers的基本操作,ARC下的运用限制。注意:本节内容是关于指针值(指针所指向的对象的地址),而不是关于指针所指的对象,指针所指的对象的运用规则将会在下一个section介绍。

有三种指针类型属于ARC管理范畴:

(1)block指针

(2)objective-c对象指针。 如id,class,NSFoo*

(3)标有_attribute_((NSObject))的类型定义(不推荐使用)

其他的指针类型,如int*,CFStringRef(也就是core Foundation类型的,带Ref后缀),不属于ARC管理范畴。


1.1 retain count 语法

指针有可能是空指针或者指向合法对象(valid object)的指针,一个合法的对象必须有reatain,release,autorelease的retain操作。

retain方法:无参,返回一个指向对象的指针

release方法:无参,返回void

autorelease方法:无参,返回一个指向对象的指针


1.2 retained return values

一个方法如果返回一个retainable对象指针,则被定义为返回一个retained value,这代表了调用此方法的caller希望变为此retainable object的第a+1个所有者。 alloc,copy,init,mutableCopy,new方法均会返回一个retainable对象指针,且retain count +1.


1.3 unretained return values

一个方法如果返回一个retainable对象类型,但是不返回一个retained value,那么我们必须确定这个对象在return边界内依然是合法的。


1.4 bridged casts(a C-style cast)

(1) (_bridge T) op;   op与T必须一个是retainable object pointer type,另一个是non-retainable pointer type。 这个cast不交换ownership,且ARC不插入retain操作。

(2)(_bridge_reatained T) op;   op必须是reatainable object pointer type, T必须是non-retainable pointer type。 ARC会有retain操作。接收者持有retain +1 。

(3)(_bridge_transfer T) op;   op必须是non-retainable pointer type, T必须是reatainable object pointer type。 ARC会在封闭的表达范围的最后release the value(ARC will release the value at the end of enclosing full-expression,subject to the usual optimizations on local values)。

(see this gay's conclusion: http://blog.csdn.net/yiyaaixuexi/article/details/8553659)


2. ownership qualification

有四种ownership qualifiers:

(1)_autorealeasing

(2)_strong

(3)_unsafe_unretained

(4)_weak

(see this gay's conclusion: http://blog.csdn.net/cuibo1123/article/details/28349793)


当我们创建一个新对象时,他的引用计数为1;

当有一个新的指针指向这个对象时,他的引用计数就加1;

当对象关联的某个指针不再指向他时,他的引用计数就减1;

当对象的引用计数为0时,说明此对象不再被任何指针指向,这时我们就可以将对象销毁,回收内存。


这篇文章非常重要:http://www.cnblogs.com/huangjianwu/p/4962772.html


接下来自己开始踩坑:

1. 第一个坑: 先来说一件不易被发现的事情

NSURL *sourceURL; //这个对象为一个全局对象。
{
sourceURL = @"xx/xx/x";

NSArrar *s = [ [sourceURL absoluteString] componentsSeparatedByString:@"/" ];
}
那么在{}结束以后,sourceURL的retainCount会变为3 。

但是换一种写法:


NSURL *sourceURL; //这个对象为一个全局对象。
{
sourceURL = @"xx/xx/x";
NSString *str = [sourceURL absoluteString];
NSArrar *s = [ str componentsSeparatedByString:@"/" ];
}
那么在{}结束以后,sourceURL的retainCount会变为2 。

2.第二个坑
uint32_t* pixels = (uint32_t*)malloc(contextLength);
    
    if(pixels == NULL) {
        NSLog(@"Error: Memory not allocated for bitmap");
        CGDataProviderRelease(provider);
        CGColorSpaceRelease(colorSpace);
        CGImageRelease(iref);
    }
    
    CGContextRef context = CGBitmapContextCreate(pixels,
                                                 imageWidth,
                                                 imageHeight,
                                                 bitsPerComponent,
                                                 bytesPerRow,
                                                 colorSpace,
                                                 bitmapInfo);
    CFRelease(colorSpace);
    free(pixels);  //请注意这里在创建context之后立刻释放pixels是可行的,也就是说context会对malloc出来的那块地址多进行一次retain count +1
    pixels = nil;  //所以我们需要对pixels这个指针进行release

(关于free(), malloc()的解释可以参考下面的链接:http://blog.csdn.net/poleness/article/details/27968709)

CFRetain、CFRelease与MRC下的retain、release功能一样, 区别于free(),free会直接将该指针所指向的那块内存释放掉。


3. CF简单的赋值是不会改变引用计数的
assign: 简单赋值,不更改索引计数
copy: 建立一个索引计数为1的对象,然后释放旧对象
retain:释放旧的对象,将旧对象的值赋予输入对象,再提高输入对象的索引计数为1

使用含有create或者copy的函数的创建的对象,使用完之后必须释放,否则将导致内存泄漏。


CFDictionaryRef option_dict = (__bridge CFDictionaryRef)options;
CFDictionaryRef option_dict2 =  option_dict;
这样的cf赋值不会增加option_dict的引用计数







你可能感兴趣的:(iOS开发:ARC下内存回收机制详解,及如何防止内存泄漏)