热门搜索 :
考研考公
您的当前位置:首页正文

iOS内存管理探底

来源:东饰资讯网

一、引用计数(保留计数)

iOS的内存管理主要是依赖引用计数,so,我们扯扯这个的工作原理:


1707017-089e69ea2340eaa6.png

二、属性修饰方法assign,weak,strong,retain,copy

image.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);

打印如下:


image.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则出现野指针


image.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

Top