iOS内存管理探底
2017-11-13 本文已影响15人
踏云小子
一、引用计数(保留计数)
iOS的内存管理主要是依赖引用计数,so,我们扯扯这个的工作原理:
![](https://img.haomeiwen.com/i1476360/c8a1123b156c95b7.png)
二、属性修饰方法assign,weak,strong,retain,copy
![](https://img.haomeiwen.com/i1476360/8ada073e57361a50.png)
2.1 retain, strong其实一个意思
2.2 copy, strong区别
- copy会重新开辟一块内存,并将源对象的内容传给新对象,是深拷贝
- strong只是将源对象的指针传给新对象,是浅拷贝,如果源对象的内容变化,新对象也跟着变化
#import <Foundation/Foundation.h>
@interface XYPerson : NSObject
@property (nonatomic,copy) NSString * name;
@property (nonatomic,strong) NSString * StrongName;
@end
测试如下
NSMutableString *name = [NSMutableString stringWithFormat:@"will is so"];
self.name = name;
self.StrongName = name;
[name appendString:@" handsome"];
NSLog(@"%@ \n %@", self.name, self.StrongName);
打印如下:
![](https://img.haomeiwen.com/i1476360/d4a7395314db582f.png)
很明显,StrongName内容发生了变化
拓展
经常有这样面试题
用@property声明的NSString(或NSArray,NSDictionary)经常使用copy关键字,为什么?如果改用strong关键字,可能造成什么问题?
答:是因为NSString、NSArray、NSDictionary有对应的可变类型NSMutableString、NSMutableArray、NSMutableDictionary,如果属性被这些可变类型赋值了,那么会导致属性无意变动,为避免这些,使用copy;如果使用strong关键字,会导致属性无意变动
2.3 strong, weak区别
区别
- strong:强引用,其存亡直接决定所指对象的存亡,在赋值时对对象进行retain操作,使引用计数+1
- weak:弱引用,其存亡不决定所指对象的存亡,若所指对象被其他强引用指向,强引用置为nil,则其所指对象也置为nil
应用
- delegate都是用
weak
修饰,为啥
两个对象各有一个强引用指向对方,会造成引用循环
image.png
当[tableView.delegate method]
就会使得delegate引用计数+1,导致无法释放,所以用@property (nonatomic, weak) id<Delegate>delegate
- block的引用循环,也可以用
__weak
破
#define RCLog(obj){if (obj){printf("retain count = %ld\n",CFGetRetainCount((__bridge CFTypeRef)(obj)));}else{printf("null \n");}}
RCLog(self);
[self block:^{
self.strongPoint = [NSDate date];
}];
RCLog(self);
打印:
retain count = 7
retain count = 8
打印引用计数,发现+1了,这里self持有block,而block又持有self,导致了引用循环,我们用__weak来解决:
RCLog(self);
__weak typeof(self) weakself=self;
[self block:^{
weakself.strongPoint = [NSDate date];
}];
RCLog(self);
打印:
retain count = 7
retain count = 7
有的block用__strong来修饰对象,是为了防止对象引用时,不会已经是nil了,举个例子:
RCLog(self);
__weak typeof(self) weakself=self;
[self block:^{
__strong typeof (self) strongself = weakself;
strongself.strongPoint = [NSDate date];
}];
RCLog(self);
打印:
retain count = 7
retain count = 7
2.4 assign, weak区别
- assign与其他的都不一样,只有他是修饰基本数据类型和结构体的,其他的都是修饰对象的
- weak与assign不一样的地方,是他指向的对象消失时候(内存释放),会自动置为nil,而assign则不会,这样给weak修饰的属性发送消息不会crash
举个例子:
#import <Foundation/Foundation.h>
@interface XYPerson : NSObject
@property (nonatomic, strong) id strongPoint;
@property (nonatomic, weak) id weakPoint;
@property (nonatomic, assign) id assignPoint;
@end
测试如下:
self.strongPoint = [NSDate date];
self.weakPoint = self.strongPoint;
self.assignPoint = self.strongPoint;
self.strongPoint = nil;
打断点,当strongPoint置为nil后,weakPoint也置为nil,而assignPoint则出现野指针
![](https://img.haomeiwen.com/i1476360/d85ae24fed2eb53b.png)
三、对象修饰方法__weak,__strong,__unsafe_unretained
3.1 __weak
弱引用,其存亡不决定所指对象的存亡,若所指对象被其他强引用指向,强引用置为nil,则其所指对象也置为nil
3.2 __strong
强引用, 默认就是__strong,其存亡直接决定所指对象的存亡,在赋值时对对象进行retain操作,使引用计数+1
- __strong -> __strong
__strong NSObject *obj1=[NSObject new];
__strong NSObject *obj2 = obj1;
obj1=nil;
NSLog(@"%@,%@",obj1,obj2);
打印如下:
(null),<NSObject: 0x60000001f6c0>
- __strong -> __weak
__strong NSObject *obj1=[NSObject new];
__weak NSObject *obj2 = obj1;
obj1=nil;
NSLog(@"%@,%@",obj1,obj2);
打印如下:
(null),(null)
3.3 __unsafe_unretained
__unsafe_unretained与__weak类似,只不过若所指对象被其他强引用指向,且强引用置为nil,则其所指对象不置为nil