Objective c 自动参考计数释放自我的新模式是什么?

Objective c 自动参考计数释放自我的新模式是什么?,objective-c,memory-management,automatic-ref-counting,nscoder,Objective C,Memory Management,Automatic Ref Counting,Nscoder,以NSObject方法-(id)awakeAfter使用coder:(NSCoder*)解码器为例,文档说明: 允许一个对象在解码后替换另一个对象 为自己。例如,表示字体的对象可能在 在解码时,释放自身并返回具有 与字体本身相同的字体描述。这样,就可以创建冗余对象 淘汰 通常你会这么做 [self release]; return substitutedObject; 使用ARC时,必须将这条线去掉。这难道不会泄露吗?或者我应该信任NSCoder对象为我释放原始对象吗?如果是这样的话,为什么首

以NSObject方法
-(id)awakeAfter使用coder:(NSCoder*)解码器
为例,文档说明:

允许一个对象在解码后替换另一个对象 为自己。例如,表示字体的对象可能在 在解码时,释放自身并返回具有 与字体本身相同的字体描述。这样,就可以创建冗余对象 淘汰

通常你会这么做

[self release];
return substitutedObject;
使用ARC时,必须将这条线去掉。这难道不会泄露吗?或者我应该信任NSCoder对象为我释放原始对象吗?如果是这样的话,为什么首先要显式地使用非ARC代码释放self


根据编译器文档对self的描述,我认为self=nil是不正确的:

我认为ARC足够聪明,可以跟踪所有对象。因此,你应该能够不说任何关于内存的事情,当它不再使用时,应用程序将释放该对象。通过leaks profiler运行它,以防万一,但它应该没问题。

如前所述,您不能编写
[self release]。另外,
awakafterusingcoder:
不是初始值设定项——您不能重新分配
self

这难道不会泄露吗

对。在下面的程序中证明

或者我应该信任NSCoder对象为我释放原始对象吗

没有

下面有一种避免泄漏的方法——我不会称之为“新模式”,这只是我想到的第一种方法。它包括显式地释放
自我
,在这种情况下,显式地保留结果:

#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;
}
#导入
@接口:NSObject
-(id)initWithBool:(bool)pBool;
-(布尔)伊斯特鲁;
-(bool)是假的;
@结束
静态NSString*const MONBoolean\u KEY\u value=@“MONBoolean\u KEY\u value”;
@布尔运算的实现
{
布尔值;
}
-(id)initWithBool:(bool)pBool
{
self=[super init];
如果(0!=self){
值=pBool;
}
回归自我;
}
-(布尔)伊斯特鲁
{
返回true==值;
}
-(bool)是假的
{
返回false==值;
}
-(NSString*)说明
{
返回[[NSString alloc]initWithFormat:@:::%s”,对象_getClassName(self),self,self.isTrue?“真”:“假”];
}
-(void)编码器与编码器:(NSCoder*)一个编码器
{
[aCoder encodeBool:value forKey:MONBoolean\u KEY\u value];
}
-(id)initWithCoder:(NSCoder*)aDecoder
{
self=[super init];
如果(0!=self){
值=[aDecoder decodeboolforky:MONBoolean_KEY_value];
}
回归自我;
}
-(id)使用编码器后醒来:(NSCoder*)编码器
{
常量布尔b=值;
//无法在初始值设定项之外重新分配self。
//如果不释放,将导致泄漏:
CFRelease((uu bridge const void*)self;
MONBoolean*结果=[[MONBoolean alloc]initWithBool:b];
//现在我们必须明确保留,因为这是
//自动释放方法:
CFRetain((uu桥梁施工无效*)结果);
返回结果;
}
@结束
int main(int argc,const char*argv[]
{
@自动释放池{
MONBoolean*a=[[MONBoolean alloc]initWithBool:true];
NSData*data=[NSKeyedArchivedDataWithRootObject:a];
MONBoolean*b=[NSKeyedUnarchiver unarchiveObjectWithData:data];
NSLog(@“%@”,b);
}
系统(“此处为流程的名称”);
返回0;
}

在Mac OS X上的NIB顶级对象上下文中也出现了类似的问题。上面说:

如果文件所有者不是
NSWindowController
NSViewController
的实例,则您需要自己减少顶级对象的引用计数。通过手动引用计数,可以通过向顶级对象发送
release
消息来实现这一点。使用ARC无法执行此操作。相反,您将顶级对象的引用转换为核心基础类型,并使用<代码> cFrRule./P>
所以,这种技术大概也可以用于这种情况<代码>CFRelease((uu桥CFTypeRef)自身)

但我的理解是,自动引用计数仍然只是引用计数。它与垃圾收集不同。因此,(理论上)当不再使用时,仍然可能有泄漏的物体。我将在分析器中运行它。您能否澄清为什么必须显式保留结果?这显然违背了ARC的目的。谢谢你回答其他问题。@moshy不客气。是的,我最初忽略了这个细节。原因是
awakafterusingcoder:
返回一个非拥有(或自动删除)的引用。因此,ARC为我们的返回值插入一个参考计数递减。我们要做的是有效地将引用从一个对象转移到另一个对象。我用仪器测试过,没有泄漏。没有僵尸。如果没有显式的retain,将向僵尸发送消息。没有明确的释放-泄漏。您可以自己尝试一下(将
@autorelease
块放在
while(1)
)中。您是否可以将该方法设置为
init
家族中具有
\u属性的成员((objc\u method\u family(init))
,然后重新分配
self
。编译器用于确定重新分配self是否有效的内容需要确认该属性。一般来说,属性不应该在这个上下文中使用(imo),但如果苹果不允许这个bug溜走的话,它会很好。您的解决方案将是他们可以采取的一种方法。如前所述,我实现了嵌入式Nib替换(使用ARC),但在使用手动释放时,旧“self”上出现了内存访问错误。我在
NSObject.h
中看到了以下内容,这使我怀疑
awake在使用coder:
后,在没有手动释放和保留的情况下正确处理了对象替换: