7

-(id)awakeAfterUsingCoder:(NSCoder *)decoder例としてNSObject メソッドを使用すると、ドキュメントには次のように記載されています。

オブジェクトがデコードされた後、それ自体を別のオブジェクトに置き換えることを許可します。たとえば、フォントを表すオブジェクトは、デコード時にそれ自体を解放し、それ自体と同じフォント記述を持つ既存のオブジェクトを返す場合があります。このようにして、冗長なオブジェクトを削除できます。

通常、あなたはそうするでしょう

[self release];
return substitutedObject;

ARC では、この行を除外する必要があります。これは漏れませんか?それとも、NSCoder オブジェクトを信頼して元のオブジェクトを解放する必要がありますか? もしそうなら、そもそもARC以外のコードで自分自身を明示的に解放しなければならないのはなぜですか?

self = nilコンパイラのドキュメントが自己について述べていることを考えると、正しいとは思いません: http://clang.llvm.org/docs/AutomaticReferenceCounting.html#misc.self

4

3 に答える 3

4

同様の問題が、Mac OS X の NIB トップレベル オブジェクトのコンテキストで発生します。リソース プログラミング ガイドには、次のように記載されています。

ファイルの所有者がNSWindowControllerまたはNSViewControllerのインスタンスでない場合は、最上位オブジェクトの参照カウントを自分で減らす必要があります。手動の参照カウントでは、トップレベル オブジェクトにreleaseメッセージを送信することでこれを実現できました。これは ARC では実行できません。代わりに、最上位オブジェクトへの参照を Core Foundation 型にキャストし、 を使用しますCFRelease

したがって、そのテクニックはおそらくこの状況でも使用できます。 CFRelease((__bridge CFTypeRef)self);

于 2012-04-22T14:19:13.720 に答える
2

前述のとおり、書き込みはできません[self release];。さらに、awakeAfterUsingCoder:初期化子ではありません。再割り当てはできませんself

これは漏れませんか?

はい。以下のプログラムで証明されています。

それとも、NSCoder オブジェクトを信頼して元のオブジェクトを解放する必要がありますか?

いいえ。

リークを回避するための 1 つのアプローチを以下に示します。これを「新しいパターン」とは呼びません。頭に浮かんだ最初のアプローチにすぎません。これには、結果の明示的な解放が含まれます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;
}
于 2012-04-22T06:32:22.190 に答える
0

ARC は、すべてのオブジェクトを追跡できるほどスマートだと思います。したがって、メモリについては何も言うことができず、アプリはオブジェクトが使用されなくなったときにオブジェクトを解放します。念のため、リーク プロファイラーを実行しますが、問題ないはずです。

于 2012-04-22T02:56:18.907 に答える