0

MyTestClass.hという名前のクラスがあるとします。

クラス構造は次のようになります

@interface MyTestClass : NSObject {

    NSString *testString;   
}

@property (nonatomic, retain)NSString * testString;

@end

.m ファイル

@implementation MyTestClass

@synthesize testString;    

-(id) init{ 

    [self setTestString:@""];           
    return self;
}

-(void)dealloc{ 

    [self.testString release];      
    testString = nil;

    [super dealloc];
}

@end

今、私はMyTestClassのオブジェクトを作成し、testStringを2 回割り当てました

MyTestClass * myTestClass = [[MyTestClass alloc] init];

[myTestClass setTestString:@"Hi"];
[myTestClass setTestString:@"Hello"];

今、私のtestStringsメモリが2回リークされていると思います!! (1 つはinit()を介して、もう 1 つは最初のsetTestStringメソッドを介して)

私は正しいですか?または、@property (nonatomic, retain)以前に割り当てられたメモリを処理/解放しますか?

または、このような場合、以下のコードのようにMyTestClass.mのsetTestString()をオーバーライドする必要がありますか?

-(void)setTestString:(NSString *)tempString{    

    [testString release];
    testString = nil;

   testString = [tempString retain];
}

この質問に関するヘルプをいただければ幸いです。

ありがとう。

4

6 に答える 6

2

この質問に関する助けをいただければ幸いです。

私はこれを、必ずしもあなたの質問に直接関係しない健全な観察を行うためのライセンスとみなします。

まず、(行ったように)保持プロパティを宣言して合成すると、自動生成されたゲッターとセッターがメモリ管理を正しく処理します。

セッターを手動で作成する場合(@synthesize既存のものでも可能です)、メモリ管理を自分で行う必要があります。trojanfoeの例のいずれかを使用してください。

質問のセッターには、testString == tempStringの場合、つまりプロパティの値をそれ自体に割り当てる場合、tempStringを効果的に解放して保持するため、ダングリングポインターをプロパティに割り当てることになりかねないというバグが含まれています。


これは安全に無視できる実装の詳細ですが、文字列リテラルなど@"blah"は実行可能ファイルにコンパイルされ、リリースされた回数に関係なく割り当てが解除されることはありません。したがって、あなたの例では、セッターが正しいメモリ管理を行わなかったとしても、リークは発生しません。


ちなみに、initメソッドの通常のパターンは

-(id) init
{
    self = [super init];
    if (self != nil)
    {
        // init stuff
    }
    return self;
}

または論理的等価物。

スーパークラスのinitメソッドを呼び出す必要があり、selfの値をnilに変更することもできるため、これを使用する習慣を身に付ける必要があります。

また、通常、オブジェクト参照を解放した後にnilに設定することは非常に良い習慣ですが、どちらの場合も、それを行う場合は不要です。1回目は変数がスコープ外になり、2回目はすぐに他のオブジェクトから変数を割り当てます。

于 2012-07-05T15:21:51.353 に答える
0

漏れではありません。合成された変数は正しく処理されます。

合成されたメソッドはこのように実装されます(retainキーワードの場合)

@property (nonatomic, retain) NSString *string;
//backed by variable NSString *_string;

- (void)setString:(NSString*)newString
{
    if (newString != _string) {
       [_string release];
       _string = [newString retain];
    }
}

もちろん、これはリークです。

- (void)aMethod //of my class with string property
{
   NSString *aString = [[NSString alloc] initWithString:@"hello"];
   self.string = aString; //retain count of 2
   self.string = @"hello2"; //retain count of 1 for aString

  //now I don't release aString.... leak

}
于 2012-07-05T14:57:22.227 に答える
0

自動生成されたセッター(この場合はsetTestString:、によっても呼び出されself.testString = ...;ます)を使用すると、プロパティの以前の値retainが解放されてから設定されます。いいえ、上記で投稿したコードにリークはありません。

于 2012-07-05T14:57:27.320 に答える
0

dsettersynthesizeメソッドは正しいことを行う必要があります。実装例は次のとおりです。

- (void)setTestString:(NSString *)tempString
{    
    [tempString retain];
    [testString release];
    testString = tempString;
}

また:

- (void)setTestString:(NSString *)tempString
{    
    if (tempString != testString)
    {
        [testString release];
        [tempString retain];
        testString = tempString;
    }
}
于 2012-07-05T14:57:35.977 に答える
0

Deallocは、インスタンスが破棄されたときにのみ呼び出されます。もし、するなら :

[myTestClass setTestString:@"Hi"];
[myTestClass setTestString:@"Hello"];

同じブロックで、セッターを2回呼び出しているだけです。メモリリークはありません。

于 2012-07-05T14:57:43.810 に答える
0

@synthesizeを指定するプロパティで使用する場合retain、生成されるセッターは、複数の割り当てに対して保持/解放を正しく処理します。self.バッキング変数に直接移動して最終リリースを行うのではなく、を使用する限り、問題はありませdeallocん。

于 2012-07-05T14:57:58.890 に答える