版本记录
版本号 | 时间 |
---|---|
V1.0 | 2017.09.06 |
前言
不管ARC还是MRC都有引用计数,不同的是MRC的引用计数需要程序员自己管理,而ARC(iOS5及iOS5以后)的引用计数程序会自动帮助管理引用计数。下面就研究一下引用计数相关的几个问题。
问题提出
今天去面试,被面试官问了一个问题,就是对象在alloc和init哪个方法调用后引用计数是否会加1,我直接有点懵逼了,我都不用MRC好久了,所以这里我就特意的提出这个问题,并在这里进行解决,给出demo,这个问题虽然不大,确是很有意思,下面我们就一起看一下。
问题验证
1. 关闭ARC,打开MRC
首先做测试之前需要先关闭ARC,打开MRC,具体操作方法如下图所示。
这里设置为NO,那么就实现了ARC关闭,MRC打开了。
2. 验证测试
下面我们就看一下测试代码。
测试1:自定义对象
1. JJMRCObjectVC.h
#import <UIKit/UIKit.h>
@interface JJMRCObjectVC : UIViewController
@end
2. JJMRCObjectVC.m
#import "JJMRCObjectVC.h"
@interface JJMRCObjectVC ()
@end
@implementation JJMRCObjectVC
- (void)viewDidLoad
{
[super viewDidLoad];
}
@end
3. JJMRCRetainCountVC.h
#import <UIKit/UIKit.h>
@interface JJMRCRetainCountVC : UIViewController
@end
4. JJMRCRetainCountVC.m
#import "JJMRCRetainCountVC.h"
#import "JJMRCObjectVC.h"
@interface JJMRCRetainCountVC ()
@end
@implementation JJMRCRetainCountVC
#pragma mark - Override Base Function
- (void)viewDidLoad
{
[super viewDidLoad];
JJMRCObjectVC *obj = [JJMRCObjectVC alloc];
NSLog(@"retainCount1 = %ld", obj.retainCount);
[obj init];
NSLog(@"retainCount2 = %ld", obj.retainCount);
[obj retain];
NSLog(@"retainCount3 = %ld", obj.retainCount);
}
@end
下面看输出结果
2017-09-07 00:09:45.870114+0800 JJOC[2429:1486715] retainCount1 = 1
2017-09-07 00:09:45.870228+0800 JJOC[2429:1486715] retainCount2 = 1
2017-09-07 00:09:45.870243+0800 JJOC[2429:1486715] retainCount3 = 2
从上面我们可以得到如下结论:
- 自定义对象实例化
alloc
的时候retainCount
就会加1。 - 自定义对象实例化
init
并不会改变引用计数。 -
retain
方法会使对象的引用计数加1。
测试2:系统对象NSString
下面看测试代码
- (void)stringObject
{
NSString *obj = [NSString alloc];
NSLog(@"retainCount1 = %ld", obj.retainCount);
[obj init];
NSLog(@"retainCount2 = %ld", obj.retainCount);
[obj retain];
NSLog(@"retainCount3 = %ld", obj.retainCount);
}
下面看输出结果
2017-09-07 00:23:07.910037+0800 JJOC[2434:1488119] retainCount1 = -1
2017-09-07 00:23:07.910093+0800 JJOC[2434:1488119] retainCount2 = -1
2017-09-07 00:23:19.438378+0800 JJOC[2434:1488119] retainCount3 = -1
测试3 :系统对象NSArray
还是直接看代码
- (void)arrayObject
{
NSArray *obj = [NSArray alloc];
NSLog(@"retainCount1 = %ld", obj.retainCount);
[obj init];
NSLog(@"retainCount2 = %ld", obj.retainCount);
[obj retain];
NSLog(@"retainCount3 = %ld", obj.retainCount);
}
看输出结果
2017-09-07 00:26:01.682392+0800 JJOC[2437:1489482] retainCount1 = -1
2017-09-07 00:26:01.682444+0800 JJOC[2437:1489482] retainCount2 = -1
2017-09-07 00:26:01.682457+0800 JJOC[2437:1489482] retainCount3 = -1
测试4 :系统对象NSDictionary
还是直接看代码
- (void)dictionaryObject
{
NSDictionary *obj = [NSDictionary alloc];
NSLog(@"retainCount1 = %ld", obj.retainCount);
[obj init];
NSLog(@"retainCount2 = %ld", obj.retainCount);
[obj retain];
NSLog(@"retainCount3 = %ld", obj.retainCount);
}
下面看输出结果
2017-09-07 00:28:28.819274+0800 JJOC[2441:1489983] retainCount1 = -1
2017-09-07 00:28:28.819330+0800 JJOC[2441:1489983] retainCount2 = -1
2017-09-07 00:28:28.819344+0800 JJOC[2441:1489983] retainCount3 = -1
测试5 :系统对象NSMutableString
- (void)mutableStringObject
{
NSMutableString *obj = [NSMutableString alloc];
NSLog(@"retainCount1 = %ld", obj.retainCount);
[obj init];
NSLog(@"retainCount2 = %ld", obj.retainCount);
[obj retain];
NSLog(@"retainCount3 = %ld", obj.retainCount);
}
下面看输出结果
2017-09-07 10:16:10.659262+0800 JJOC[2499:1516892] retainCount1 = -1
2017-09-07 10:16:10.659306+0800 JJOC[2499:1516892] retainCount2 = -1
2017-09-07 10:16:15.259583+0800 JJOC[2499:1516892] retainCount3 = -1
测试6:系统对象NSMutableArray
- (void)mutableArrayObject
{
NSMutableArray *obj = [NSMutableArray alloc];
NSLog(@"retainCount1 = %ld", obj.retainCount);
[obj init];
NSLog(@"retainCount2 = %ld", obj.retainCount);
[obj retain];
NSLog(@"retainCount3 = %ld", obj.retainCount);
}
下面看输出结果
2017-09-07 10:18:17.567898+0800 JJOC[2502:1517294] retainCount1 = -1
2017-09-07 10:18:17.567940+0800 JJOC[2502:1517294] retainCount2 = -1
2017-09-07 10:18:17.567954+0800 JJOC[2502:1517294] retainCount3 = -1
测试7:系统对象NSMutableDictionary
- (void)mutableDictionaryObject
{
NSMutableDictionary *obj = [NSMutableDictionary alloc];
NSLog(@"retainCount1 = %ld", obj.retainCount);
[obj init];
NSLog(@"retainCount2 = %ld", obj.retainCount);
[obj retain];
NSLog(@"retainCount3 = %ld", obj.retainCount);
}
下面看输出结果
2017-09-07 10:20:17.433409+0800 JJOC[2504:1517831] retainCount1 = -1
2017-09-07 10:20:17.433466+0800 JJOC[2504:1517831] retainCount2 = -1
2017-09-07 10:20:17.433481+0800 JJOC[2504:1517831] retainCount3 = -1
从上面大家也会看到:测试2、3、4、5、6和7中由于使用的都是系统的类(NSString、NSArray 和 NSDictionary以及它们三个的可变形式对象)
,那么它们在实例化对象的时候,引用计数均为-1,这又是因为什么呢?
看苹果的开发文档,大家会看到这么一句
You might override this method in a class to implement your own reference-counting scheme. For objects that never get released (that is, their release method does nothing), this method should return UINT_MAX
意思就是:你可以重写这个方法实现自己的引用计数,对于从来不会释放的对象(也可以说,它们的释放方法什么都没做),那么这个方法会返回UINT_MAX
。也就是说对于一些对象系统不会去释放掉,那么它的引用计数就是-1或者UINT_MAX
。
也可以这么理解,看苹果的开发文档,上面写着应该返回的是这个对象的UINT_MAX
, 并且不会释放, 这个UINT_MAX,最大二进制为(11111111111111111111111111111111)
也是十六进制(0xffffffff)
,如果你当成有符号数取补码后输出就得-1
;如果你当成无符号数就是最大数即:18446744073709551615
。
参考文章
1. 关于OC中的alloc init方法
2. 关于NSString的retainCount的各种结果原因
3. iOS 切换到MRC环境下打印 retainCount 始终是-1或者一长串证书
后记
未完,待续~~~