0

私は Obj-C の初心者で、いくつかのことを試しています。1 つのリークの問題に出くわしました。その背後にある論理的な理由を知りたいと思います。

次のコードがリークしています:

(textViewAttrStr is an instance variable of type NSMutableAttributedString)

-(void) init:(NSString*)str
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

textViewAttrStr = [[NSMutableAttributedString alloc] initWithString:@"Hello "];
NSMutableAttributedString *part1String = [[NSMutableAttributedString alloc] initWithString:str];
[textViewAttrStr appendAttributedString:part1String];
NSMutableAttributedString *part2String = [[NSMutableAttributedString alloc] initWithString:@"!!!"];
[textViewAttrStr appendAttributedString:part2String];
[textViewAttrStr retain];

[part1String release];
[part2String release];

[pool drain];
}

-(void) dealloc
{
if(textViewAttrStr != nil)
{
    [textViewAttrStr release];
}

[super dealloc];
}

次のコードはリークしません:

-(void) init:(NSString*)str
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

NSMutableAttributedString* tvas = [[NSMutableAttributedString alloc] initWithString:@"Hello "];
NSMutableAttributedString *part1String = [[NSMutableAttributedString alloc] initWithString:str];
[tvas appendAttributedString:part1String];
NSMutableAttributedString *part2String = [[NSMutableAttributedString alloc] initWithString:@"!!!"];
[tvas appendAttributedString:part2String];

textViewAttrStr = tvas;
[textViewAttrStr retain];

[part1String release];
[part2String release];
[tvas release];

[pool drain];
}

-(void) dealloc
{
if(textViewAttrStr != nil)
{
    [textViewAttrStr release];
}

[super dealloc];
}

誰かが理由を説明できますか?

4

3 に答える 3

2

最初の例の問題は、追加の保持です。textViewAttrStrwithを作成したときにすでに保持されているため、それを削除する必要があります[[NSMutableAttributedString alloc] initWithString:@"Hello "];

//Remove this line in the first example
[textViewAttrStr retain];
于 2011-08-11T14:25:54.153 に答える
1

最初の例:

textViewAttrStr = [[NSMutableAttributedString alloc] initWithString:@"Hello "]; 
//...
[textViewAttrStr retain];

2 番目の例

NSMutableAttributedString* tvas = [[NSMutableAttributedString alloc] initWithString:@"Hello "];
//...
[tvas release];

最初の例では、割り当て/初期化して保持したことがわかります。

2番目の例では、適切に割り当て/初期化してから解放しました。

単純なルール: 割り当て/初期化またはコピーまたは保持する場合、ある時点で解放する必要があります。クラス変数の場合は、dealloc で解放します。それ以外の場合は、スコープを離れる前に解放します。

于 2011-08-11T14:25:35.343 に答える
0

2 番目の例は、最初の例でリークが発生した理由を理解していないことを示しているため、実験することを選択しましたが、これは理解できるアプローチのようです。

2 番目の例では、 textViewAttrStr と tavs は本質的に同じです。どちらもメモリ内の同じオブジェクトへの参照 (またはポインター) です。

だから、あなたがするとき:

textViewAttrStr = tvas;
[textViewAttrStr retain];
//...
[tvas release];

このオブジェクトの保持の呼び出しは、このオブジェクトの解放の呼び出しとバランスが取れています。これはほとんど何もしていません。ここで保持呼び出しと解放呼び出しを削除すると、同じ機能が提供されます。これらを削除すると、alloc を呼び出したため、オブジェクトの参照カウントは 1 になり、dealloc がヒットすると、オブジェクトは 0 に達して解放されます。

さて、最初の例では、オブジェクトが割り当てられ (参照カウント 1)、保持されます (参照カウント 2)。dealloc がヒットすると、参照カウント 1 に達し、オブジェクトは解放されず、したがって漏れます。したがって、ここでの解決策は、retain への呼び出しを削除することです。

ちなみに、解放メッセージをオブジェクトに送信する前に、オブジェクトが nil でないかどうかを確認する必要はありません。nil にメッセージを送信しても何も起こらないからです。

于 2011-08-12T03:22:43.557 に答える