7

以 NSObject 方法-(id)awakeAfterUsingCoder:(NSCoder *)decoder为例,文档说:

允许一个对象在被解码后,用另一个对象代替它自己。例如,表示字体的对象可能在被解码后释放自身并返回与自身具有相同字体描述的现有对象。这样,可以消除多余的对象。

通常你会做

[self release];
return substitutedObject;

使用 ARC,您必须将这条线排除在外。这不会泄露吗?还是我应该相信 NSCoder 对象会为我释放原始对象?如果是这样,为什么您必须首先使用非 ARC 代码显式释放 self ?

self = nil鉴于编译器文档对自我的说法,我认为这是不正确的:http: //clang.llvm.org/docs/AutomaticReferenceCounting.html#misc.self

4

3 回答 3

4

A similar issue arises in the context of NIB top-level objects on Mac OS X. The Resource Programming Guide says:

If the File’s Owner is not an instance of NSWindowController or NSViewController, then you need to decrement the reference count of the top level objects yourself. With manual reference counting, it was possible to achieve this by sending top-level objects a release message. You cannot do this with ARC. Instead, you cast references to top-level objects to a Core Foundation type and use CFRelease.

So, that technique can presumably be used in this situation, too. CFRelease((__bridge CFTypeRef)self);

于 2012-04-22T14:19:13.720 回答
2

如前所述,您不能编写[self release];. 此外,awakeAfterUsingCoder:不是初始化器——您不能重新分配self.

这不会泄露吗?

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

还是我应该相信 NSCoder 对象会为我释放原始对象?

不。

One approach to avoid the leak exists below -- I would not call it "the new pattern", just the first approach that came to mind. It involves an explicit release of self and in this case an explicit retain of the result:

#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;
}
于 2012-04-22T06:32:22.190 回答
0

我相信 ARC 足够聪明,可以跟踪所有对象。因此,您应该能够对内存不说任何内容,并且应用程序将在不再使用该对象时释放该对象。以防万一,通过泄漏分析器运行它,但应该没问题。

于 2012-04-22T02:56:18.907 回答