版本記錄
版本號 | 時間 |
---|---|
V1.0 | 2017.09.06 |
前言
不管ARC還是MRC都有引用計數(shù),不同的是MRC的引用計數(shù)需要程序員自己管理,而ARC(iOS5及iOS5以后)的引用計數(shù)程序會自動幫助管理引用計數(shù)。下面就研究一下引用計數(shù)相關(guān)的幾個問題。
問題提出
今天去面試,被面試官問了一個問題,就是對象在alloc和init哪個方法調(diào)用后引用計數(shù)是否會加1,我直接有點懵逼了,我都不用MRC好久了,所以這里我就特意的提出這個問題,并在這里進行解決,給出demo,這個問題雖然不大,確是很有意思,下面我們就一起看一下。
問題驗證
1. 關(guān)閉ARC,打開MRC
首先做測試之前需要先關(guān)閉ARC,打開MRC,具體操作方法如下圖所示。
這里設(shè)置為NO,那么就實現(xiàn)了ARC關(guān)閉,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
下面看輸出結(jié)果
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
從上面我們可以得到如下結(jié)論:
- 自定義對象實例化
alloc
的時候retainCount
就會加1。 - 自定義對象實例化
init
并不會改變引用計數(shù)。 -
retain
方法會使對象的引用計數(shù)加1。
測試2:系統(tǒng)對象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);
}
下面看輸出結(jié)果
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 :系統(tǒng)對象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);
}
看輸出結(jié)果
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 :系統(tǒng)對象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);
}
下面看輸出結(jié)果
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 :系統(tǒng)對象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);
}
下面看輸出結(jié)果
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:系統(tǒng)對象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);
}
下面看輸出結(jié)果
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:系統(tǒng)對象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);
}
下面看輸出結(jié)果
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中由于使用的都是系統(tǒng)的類(NSString、NSArray 和 NSDictionary以及它們?nèi)齻€的可變形式對象)
,那么它們在實例化對象的時候,引用計數(shù)均為-1,這又是因為什么呢?
看蘋果的開發(fā)文檔,大家會看到這么一句
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
意思就是:你可以重寫這個方法實現(xiàn)自己的引用計數(shù),對于從來不會釋放的對象(也可以說,它們的釋放方法什么都沒做),那么這個方法會返回UINT_MAX
。也就是說對于一些對象系統(tǒng)不會去釋放掉,那么它的引用計數(shù)就是-1或者UINT_MAX
。
也可以這么理解,看蘋果的開發(fā)文檔,上面寫著應(yīng)該返回的是這個對象的UINT_MAX
, 并且不會釋放, 這個UINT_MAX,最大二進制為(11111111111111111111111111111111)
也是十六進制(0xffffffff)
,如果你當成有符號數(shù)取補碼后輸出就得-1
;如果你當成無符號數(shù)就是最大數(shù)即:18446744073709551615
。
參考文章
1. 關(guān)于OC中的alloc init方法
2. 關(guān)于NSString的retainCount的各種結(jié)果原因
3. iOS 切換到MRC環(huán)境下打印 retainCount 始終是-1或者一長串證書
后記
未完,待續(xù)~~~