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);