22

initメソッドで保持プロパティをnilに初期化するためにドット表記を使用するのは悪い考えですか?

このような通常のプロパティでは:

@property (nonatomic, retain) id foo;

私が設定したinitメソッドで言いますself.foo = nil。合成されたメソッドは、最初にリリースまたは自動リリースしますfoo(基になる実装が正確にわからない)。foo最初のセッターまたはゲッターの呼び出しの前にゼロであることが保証されていますか?foo = nilまたは、ドット表記なしで明示的に設定しない限り、ランダムなガベージを指しますか?

4

1 に答える 1

77

initメソッドで保持プロパティをnilに初期化するためにドット表記を使用するのは悪い考えですか?

はい、それは悪い考えです。

alloc1)オブジェクトは+シーケンスですでにゼロにinitなっているため、nilを割り当てる必要はありません。つまり、アクセサに副作用がない限り、この呼び出しは役に立ちません(アクセサの副作用もこの段階で回避する必要があります)。

2)部分的に構築された状態(例および)にあるときにオーバーライドされるメソッドを使用して、自分自身にメッセージを送信しないでください。initdealloc

#2の理由はありますか?私はよくself.array=[NSMutableArray array]; 私のinitメソッドで。

init...その理由は、部分的に構築された状態( 、、、、および多くの実装)の間dealloc、オブジェクトがクラスインターフェイスの動作に関心を持ってはならないためです。クラスは、(のように)適切に初期化し、副作用を導入せずに(のように)そのメンバーを含めて自分自身の後でクリーンアップすることに関心があるはずです。finalizecopyWithZone:init...dealloc

この例を考えてみましょう。これは、OSXのFoundationツールとして構築できます。

#import <Foundation/Foundation.h>

enum { UseItTheRightWay = true -OR- false };

@interface MONObjectA : NSObject
{
    NSMutableArray * array;
}

@property (nonatomic, retain) NSArray * array;

@end

@implementation MONObjectA

@synthesize array;

- (id)init
{
    self = [super init];
    if (0 != self) {
        NSLog(@"%s, %@",__PRETTY_FUNCTION__, self);
        if (UseItTheRightWay) {
            array = [NSMutableArray new];
        }
        else {
            self.array = [NSMutableArray array];
        }
    }
    return self;
}

- (void)dealloc
{
    NSLog(@"%s, %@",__PRETTY_FUNCTION__, self);
    if (UseItTheRightWay) {
        [array release], array = nil;
    }
    else {
        self.array = nil;
    }
    [super dealloc];
}

@end

@interface MONObjectB : MONObjectA
{
    NSMutableSet * set;
}

@end

@implementation MONObjectB

- (id)init
{
    self = [super init];
    if (0 != self) {
        NSLog(@"%s, %@",__PRETTY_FUNCTION__, self);
        set = [NSMutableSet new];
    }
    return self;
}

- (void)dealloc
{
    NSLog(@"%s, %@",__PRETTY_FUNCTION__, self);
    [set release], set = nil;
    [super dealloc];
}

- (void)setArray:(NSArray *)arg
{
    NSLog(@"%s, %@",__PRETTY_FUNCTION__, self);
    NSMutableSet * tmp = arg ? [[NSMutableSet alloc] initWithArray:arg] : nil;
    [super setArray:arg];
    [set release];
    set = tmp;
}

@end

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    [[MONObjectB new] release];

    /* the tool must be named 'Props' for this to work as expected, or you can just change 'Props' to the executable's name */
    system("leaks Props");

    [pool drain];
    return 0;
}

このテストで動作を切り替えるための主なスイッチはUseItTheRightWayです。

trueの場合、次の結果が得られますUseItTheRightWay

2011-05-09 01:52:11.175 Props[45138:a0f] -[MONObjectA init], <MONObjectB: 0x10010c750>
2011-05-09 01:52:11.177 Props[45138:a0f] -[MONObjectB init], <MONObjectB: 0x10010c750>
2011-05-09 01:52:11.179 Props[45138:a0f] -[MONObjectB dealloc], <MONObjectB: 0x10010c750>
2011-05-09 01:52:11.179 Props[45138:a0f] -[MONObjectA dealloc], <MONObjectB: 0x10010c750>
leaks Report Version:  2.0
Process:         Props [45138]
< --- snip --- >        
Process 45138: 1581 nodes malloced for 296 KB
Process 45138: 0 leaks for 0 total leaked bytes.

そして、UseItTheRightWayfalseの場合、結果が与えられます。

2011-05-09 01:55:51.611 Props[45206:a0f] -[MONObjectA init], <MONObjectB: 0x10010c750>
2011-05-09 01:55:51.614 Props[45206:a0f] -[MONObjectB setArray:], <MONObjectB: 0x10010c750>
2011-05-09 01:55:51.615 Props[45206:a0f] -[MONObjectB init], <MONObjectB: 0x10010c750>
2011-05-09 01:55:51.617 Props[45206:a0f] -[MONObjectB dealloc], <MONObjectB: 0x10010c750>
2011-05-09 01:55:51.618 Props[45206:a0f] -[MONObjectA dealloc], <MONObjectB: 0x10010c750>
2011-05-09 01:55:51.618 Props[45206:a0f] -[MONObjectB setArray:], <MONObjectB: 0x10010c750>
leaks Report Version:  2.0
Process:         Props [45206]
 < --- snip --- >    
Process 45206: 1585 nodes malloced for 297 KB
Process 45206: 1 leak for 48 total leaked bytes.
Leak: 0x100110970  size=48  zone: DefaultMallocZone_0x100005000 instance of 'NSCFSet', type ObjC, implemented in Foundation 
    0x70294ff8 0x00007fff 0x00001080 0x00000001     .O)p............
    0x00000001 0x00000000 0x00000000 0x00010000     ................
    0x707612a8 0x00007fff 0x00000000 0x00000000     ..vp............

問題#1

この例の明らかな失敗は、で導入されたリークdeallocです。

問題#2

あなたを噛む2番目のことは微妙です:

-[MONObjectA init]
-[MONObjectB setArray:]
-[MONObjectB init]

これは何ですか???前に-[MONObjectB setArray:]呼び出されますか?つまり、の実装は、が終了する、および終了する前でも使用されます。それは良くない=\ -[MONObjectB init]MONObjectB -[MONObjectB init]-[MONObjectA init]

自明でない設計では、望ましくない副作用、奇妙な動作、リークなどが大量に発生します。複雑な設計は非常に明白で非常に微妙な方法で失敗し、追跡するのが非常に困難になる可能性があります。このような些細な書き方の違いによるメンテナンスの頭痛の種を避け、最初から適切な方法でクラスを書くのが最善です(明らかな副作用なしに、これをかなりの時間行うことができたとしても)。

于 2011-05-09T05:04:56.230 に答える