iOS中的retainCount – iPhone手機開發技術文章 iPhone軟體開發教學課程

我們都知道iOS中采用引用計數的技術來管理內存,當一個對象沒有任何一個地方引用的時候會自動釋放,此時的retainCount為0,而且提供瞭一個-(NSInteger)retainCount的方法來獲得對象當前的持有數。

這個概念清楚而明確,不過,讓我們看兩段代碼:

    NSNumber *number = [NSNumber numberWithInt:1];
    NSLog(@"retainCount = %lu",[number retainCount]);

這段代碼的運行結果是什麼?

    NSString *string = [NSString stringWithFormat:@"foo"];
    NSLog(@"retainCount = %lu", [string retainCount]);

這一段呢?

在Xcode5.0, ARC關閉的情況下運行,結果是:

2014-01-13 22:08:13.217 blockTest[2732:303] retainCount = 9223372036854775807

2014-01-13 22:08:13.218 blockTest[2732:303] retainCount = 1

這個很出人意料啊,第二段看上去很符合我們的預期,但第一段就有點讓人掉眼鏡瞭。

查閱瞭一下官方的文檔,第一句就是“Do not use this method.”,後面給出瞭說明,因為Autorelease pool的存在,對於內存的管理會相當復雜,retainCount就不能用作調試內存時的依據瞭。這樣對於第一段的結果就可以理解瞭,可能系統對於這一個特殊的對象有特殊的處理(沒準framework裡面有早就創建瞭這個對象瞭),於是我們拿到瞭一個非常出人意料的結果。

想想見過的如下的代碼就很有點嚇人瞭:

    while ([a retainCount] > 0) {
        [a release];
    }

如果運行結果正確,那麼這是多麼幸運的一個人啊!

但對於內存的思考我們可以更進一步,看一段代碼:

#import 

@interface Person : NSObject

@property(nonatomic, retain) NSString *name;
@property(nonatomic, assign) NSInteger age;

@end

@implementation Person
- (id)init
{
    self = [super init];
    if (self) {
        self.name = @"name";
        self.age = 20;
    }
    return self;
}

- (void)dealloc
{
    NSLog(@"dealloc");
    [super dealloc];
}

@end

int main(int argc, const char * argv[])
{
    Person *per1 = [[Person alloc] init];
    //NSLog(@"retainCount = %lu -- 0",[per1 retainCount]);
    [per1 release];
    per1.age = 22;
    NSLog(@"retainCount = %lu -- 1, age = %ld",[per1 retainCount], per1.age);
    //[per1 retain];
    //per1.age = 23;
    //NSLog(@"retainCount = %lu -- 2, age = %ld",[per1 retainCount], per1.age);
    
    return 0;
}

這段代碼的運行結果居然是:

2014-01-13 22:17:11.619 blockTest[2758:303] dealloc

2014-01-13 22:17:11.621 blockTest[2758:303] retainCount = 1 — 1, age = 22

這個問題位於https://www.cocoachina.com/ask/questions/show/106777#36483,個人猜測是對象確實銷毀瞭,畢竟dealloc都調用瞭,但內存裡面數據仍然存在,立刻打印是存在內容的,至於retainCount不是0,隻能說明對象即使已經銷毀瞭,這個值仍然可能大於0。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。