引用計數(shù)相關(guān)幾個問題(一) —— alloc init 引用計數(shù)

版本記錄

版本號 時間
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ù)~~~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容