[英]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 Stevenson的Objective-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.