簡體   English   中英

自動釋放如何在Objective-C中工作?

[英]How does autoreleasing work in Objective-C?

我只是閱讀實用內存管理指南。

我對這段代碼感到有些困惑:

- (void)printHello {
    NSString *string;
    string = [NSString stringWithFormat:@"Hello"];
    NSLog(@"%@", string);
}

在我看來,字符串的引用計數為0.這是真的嗎?

什么阻止字符串在我們調用NSLog(string)之前被釋放?

這在某種程度上等同於此:

- (void)printHello {
    NSString *string;
    string = [[[NSString stringWithFormat:@"Hello"] retain] autorelease];
    NSLog(@"%@", string);
}

編輯 :類似地,此代碼在實用內存管理指南中給出:

- (NSString *)fullName {
    NSString *string = [NSString stringWithFormat:@"%@ %@", firstName, lastName];
    return string;
}

何時以及如何釋放返回值? 誰是老板? fullName的調用者是否需要釋放全名返回的字符串?

首先:

NSLog(string);

不要這樣做。 (我剛剛意識到它來自Apple文檔。很奇怪。) NSLog的第一個參數是格式化字符串。 如果你的string包含一些百分比轉義,那么壞事就會發生。 正確的,如果稍長的方式是:

NSLog(@"%@", string);

現在到了這一點:自動釋放的對象沒有零保留計數。 他們保留計數1+並且對他們進行掛起的-1操作,這將在“未來很快”發生。

“很快將來”的確切含義取決於具體情況。 如果您在主線程上並且沒有其他自動釋放池,則自動釋放的對象將在下一個runloop迭代中釋放。 如果您有其他發布池,則不必如此:

// Let’s pretend this is a long loop and you don’t want to wait
// for the autoreleased objects to be collected by the main pool.
for (…) {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    NSString *foo = [NSString stringWith…];
    [pool drain];
    // Now foo is no longer valid.
}

至於返回自動釋放的對象,這是自動釋放的主要用例之一。 你正在返回一個將很快消失的對象,但如果調用者感興趣,他可以保留並接管所有權。 (就像你赦免圖像一樣,用燃燒的安全保險絲傳遞炸彈。如果來電者有興趣,他會通過保留來放出保險絲。)如果來電者不感興趣,可能他會忽略輸出從一個函數或只是使用該值來構造一些其他對象,他沒有做任何事情,對象將失去內存:

- (id) createObject {
    return [NSString stringWith…];
}

- (void) interestedCaller {
    NSString *value = [[self createObject] retain];
}

- (void) notInterestedCaller {
    [self createObject]; // maybe just interested in side effects
    NSString *differentString = [NSString stringWithString:[self createObject]];
}

這非常方便,使手動內存管理非常愉快。 您可能對運行循環Scott StevensonObjective-C教程感興趣。

嚴格來講,

- (void)printHello {
    NSString *string;
    string = [NSString stringWithFormat:@"Hello"];
    NSLog(@"%@", string);
}

不等於

- (void)printHello {
    NSString *string;
    string = [[[NSString stringWithFormat:@"Hello"] retain] autorelease];
    NSLog(@"%@", string);
}

慣例是一個方法應該自動釋放它返回的任何對象。 唯一的例外(AFAIK)是構造函數,它返回一個具有+1保留計數的對象。 由於[NSString stringWithFormat:]返回一個對象。 在第一個片段中, stringWithFormat:返回一個已經自動釋放的對象。 第二個片段,你再次保留它,它將被釋放兩次(具有相同的效果,但第二個保留/自動釋放對是多余的)。

好的,現在回答你的問題。 基本上,每次UIKit調用您的代碼時,它都會創建一個NSAutoreleasePool對象。 每次自動釋放對象時,都會將其添加到此池中。 最后,當您的代碼返回到UIKit時,它會調用池上的drain方法(即[pool drain] )並釋放已添加到池中的每個對象並釋放池。 此外,自動釋放池可以嵌套,因此如果您要創建大量自動釋放的對象,則可以創建自己的池並將其耗盡。 它並不像聽起來那么復雜。

我強烈建議您閱讀“內存管理指南”中的“ 自動釋放池”章節(順便提一下 ,就在“ 實用內存管理”一章之后)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM