阅读本文前,建议移步先去了解下内存管理相关知识。
1: iOS内存管理机制(百度goole大法可以获得很多推荐)。
2: iOS中的动态内存分配
3: 堆栈的原理:堆栈 百科
1:自动释放池的常见问题:
较大的循环时如果不及时释放,可能会导致内存暴涨。
for (int i = 0; i < 100000; i ++) {
@autoreleasepool { //解决方案:逐条释放,避免暴涨
NSString * log = [NSString stringWithFormat:@"%d", i];
NSLog(@"%@", log); }
}
2: 修饰符的常见问题:
ARC提供四种修饰符,分别是strong, weak, autoreleasing, unsafe_unretained
__strong:强引用,持有所指向对象的所有权,无修饰符情况下的默认值。如需强制释放,可置nil。
比如我们常用的定时器:
NSTimer * timer = [NSTimer timerWith...];
相当于
NSTimer * __strong timer = [NSTimer timerWith...];
当不需要使用时,强制销毁定时器
[timer invalidate];
timer = nil;
__weak:弱引用,不持有所指向对象的所有权,引用指向的对象内存被回收之后,引用本身会置nil,避免野指针。
比如避免循环引用的弱引用声明:
__weak __typeof(self) weakSelf = self;
ps: 诸如网络请求的时候避免弱指针丢掉,往往需要在block内部从新strong下该指针。
__strong __typeof(weakSelf) strongSelf = weakSelf;
__autoreleasing:自动释放对象的引用,一般用于传递参数
比如一个读取数据的方法
- (void)loadData:(NSError **)error;
当你调用时会发现这样的提示
NSError * error;
[dataTool loadData:(NSError *__autoreleasing *)]
这是编译器自动帮我们插入以下代码
NSError * error;
NSError * __autoreleasing tmpErr = error;
[dataTool loadData:&tmpErr];
__unsafe_unretained:为兼容iOS5以下版本的产物,可以理解成MRC下的weak,现在基本用不到,这里不作描述。
3. 属性的内存管理
ObjC2.0引入了@property,提供成员变量访问方法、权限、环境、内存管理类型的声明,下面主要说明ARC中属性的内存管理。
属性的参数分为三类,基本数据类型默认为(atomic,readwrite,assign),对象类型默认为(atomic,readwrite,strong),其中第三个参数就是该属性的内存管理方式修饰,修饰词可以是以下之一:
1)assign:直接赋值
assign一般用来修饰基本数据类型
@property (nonatomic, assign) NSInteger count;
当然也可以修饰ObjC对象,但是不推荐,因为被assign修饰的对象释放后,指针还是指向释放前的内存,在后续操作中可能会导致内存问题引发崩溃。(!!!!!bug预警)
2)retain:release旧值,再retain新值(引用计数+1)
retain和strong一样,都用来修饰ObjC对象。
使用set方法赋值时,实质上是会先保留新值,再释放旧值,再设置新值,避免新旧值一样时导致对象被释放的的问题。
MRC写法如下
- (void)setCount:(NSObject *)count {
[count retain];
[_count release];
_count = count;
}
ARC对应写法
- (void)setCount:(NSObject *)count {
_count = count;
}
3)copy:release旧值,再copy新值(拷贝内容)
一般用来修饰String、Dict、Array等需要保护其封装性的对象,尤其是在其内容可变的情况下,因此会拷贝(深拷贝)一份内容給属性使用,避免可能造成的对源内容进行改动。
使用set方法赋值时,实质上是会先拷贝新值,再释放旧值,再设置新值。
实际上,遵守NSCopying的对象都可以使用copy,当然,如果你确定是要共用同一份可变内容,你也可以使用strong或retain。
@property (nonatomic, copy) NSString * name;
4)weak:ARC新引入修饰词,可代替assign,比assign多增加一个特性(置nil,见上文)。 weak和strong一样用来修饰ObjC对象。
使用set方法赋值时,实质上不保留新值,也不释放旧值,只设置新值。
比如常用的代理的声明
@property (weak) id delegate;
Xib控件的引用
@property (weak, nonatomic) IBOutlet UIImageView *productImage;
5)strong:ARC新引入修饰词,可代替retain
可参照retain,这里不再作描述。
4. block的内存管理
iOS中使用block必须自己管理内存,错误的内存管理将导致循环引用等内存泄漏问题,这里主要说明在ARC下block声明和使用的时候需要注意的两点:
1)如果你使用@property去声明一个block的时候,一般使用copy来进行修饰(当然也可以不写,编译器自动进行copy操作),尽量不要使用retain。
@property (nonatomic, copy) void(^block)(NSData * data);
2)block会对内部使用的对象进行强引用,因此在使用的时候应该确定不会引起循环引用,当然保险的做法就是添加弱引用标记。
__weak typeof(self) weakSelf = self;