7

使用NSObject的方法-(id)awakeAfterUsingCoder:(NSCoder *)decoder作爲一個例子,文檔說:自動參考計數自釋放的新模式是什麼?

允許對象,被解碼後,以另對象 自明。例如,代表字體的對象在解碼後可能會自行釋放並返回一個與其自身字體描述相同的現有對象。通過這種方式,可以省去多餘的對象。

通常你會

[self release]; 
return substitutedObject; 

隨着ARC你要出去離開這一行。這不會泄漏嗎?或者我應該相信NSCoder對象爲我釋放原始對象?如果是這樣,你爲什麼要首先明確地釋放自己與非ARC代碼?

我不認爲self = nil是在什麼樣的編譯文件說,對自我正確的光:http://clang.llvm.org/docs/AutomaticReferenceCounting.html#misc.self

回答

2

如上所述,您不能編寫[self release];。此外,awakeAfterUsingCoder:不是初始化程序 - 您可能不會重新指定self

不會泄漏嗎?

是的。在下面的程序中證明。

或者我應該相信NSCoder對象爲我釋放原始對象?

一個是爲避免泄漏的方法存在如下 - 我不會把它稱爲「新模式」,只是浮現在腦海的第一種方法。它涉及的self明確的釋放,在這種情況下,明確保留結果

#import <Foundation/Foundation.h> 

@interface MONBoolean : NSObject <NSCoding> 

- (id)initWithBool:(bool)pBool; 

- (bool)isTrue; 
- (bool)isFalse; 

@end 

static NSString * const MONBoolean_KEY_value = @"MONBoolean_KEY_value"; 

@implementation MONBoolean 
{ 
    bool value; 
} 

- (id)initWithBool:(bool)pBool 
{ 
    self = [super init]; 
    if (0 != self) { 
     value = pBool; 
    } 
    return self; 
} 

- (bool)isTrue 
{ 
    return true == value; 
} 

- (bool)isFalse 
{ 
    return false == value; 
} 

- (NSString *)description 
{ 
    return [[NSString alloc] initWithFormat:@"<%s:%p> : %s", object_getClassName(self), self, self.isTrue ? "true" : "false"]; 
} 

- (void)encodeWithCoder:(NSCoder *)aCoder 
{ 
    [aCoder encodeBool:value forKey:MONBoolean_KEY_value]; 
} 

- (id)initWithCoder:(NSCoder *)aDecoder 
{ 
    self = [super init]; 
    if (0 != self) { 
     value = [aDecoder decodeBoolForKey:MONBoolean_KEY_value]; 
    } 
    return self; 
} 

- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder 
{ 
    const bool b = value; 
    // cannot reassign self outside of an initializer. 
    // if not released, will result in a leak: 
    CFRelease((__bridge const void*)self); 
    MONBoolean * result = [[MONBoolean alloc] initWithBool:b]; 
    // now we have to retain explicitly because this is 
    // an autoreleasing method: 
    CFRetain((__bridge const void*)result); 
    return result; 
} 

@end 

int main(int argc, const char * argv[]) 
{ 
    @autoreleasepool { 
     MONBoolean * a = [[MONBoolean alloc] initWithBool:true]; 
     NSData * data = [NSKeyedArchiver archivedDataWithRootObject:a]; 
     MONBoolean * b = [NSKeyedUnarchiver unarchiveObjectWithData:data]; 
     NSLog(@"%@", b); 
    } 
    system("leaks NAME_OF_PROCESS_HERE"); 
    return 0; 
} 
+0

你能澄清爲什麼你必須明確保留結果嗎?這當然會擊敗ARC的目的。感謝您回答所有其他問題。 – jamesmoschou 2012-04-23 09:24:46

+0

@莫西歡迎您。是的 - 我最初忽略了那個細節。原因是'awakeAfterUsingCoder:'返回一個非擁有(或自動釋放)的引用。因此,ARC會爲我們的返回值插入一個引用計數遞減量。我們想要做的是有效地將參考從一個對象轉移到另一個對象。我用儀器運行它 - 沒有泄漏。沒有殭屍。如果沒有明確的保留,殭屍會被髮送。沒有明確的釋放 - 泄漏。自己嘗試一下(把'@ autorelease'塊放在'while(1)')中。 – justin 2012-04-23 09:49:58

+1

你可以用'__attribute __((objc_method_family(init)))'方法使該方法成爲'init'家族的成員,然後重新指派'self'嗎? – 2012-05-29 21:55:32

0

我相信ARC是足夠聰明的跟蹤所有對象。所以你應該能夠不說任何關於內存的東西,而應用程序會在不再使用的時候釋放對象。爲了以防萬一,通過泄漏分析器運行它,但它應該沒問題。

+4

但我的理解是,自動引用計數仍然只是引用計數。它與垃圾收集不同。因此,當它們不再被使用時,它仍然(理論上)有可能泄漏物體。我將通過分析器運行它。 – jamesmoschou 2012-04-22 03:03:25

4

類似的問題在NIB頂級對象的Mac OS X上的方面出現的Resource Programming Guide說:

如果文件的所有者不是NSWindowControllerNSViewController的實例,那麼你需要的頂層對象自己遞減引用計數。通過手動引用計數,可以通過向頂級對象發送release消息來實現此目的。你不能用ARC做這個。相反,您將對頂級對象的引用轉換爲Core Foundation類型,並使用CFRelease

因此,這種技術也可能在這種情況下使用。 CFRelease((__bridge CFTypeRef)self);