目的 cObj
で、NSMutableArray に格納されたオブジェクトがあり、それへの配列のポインターがObj
プログラム全体で唯一の強力なポインターであるとします。でメソッドを呼び出し、Obj
このメソッドを別のスレッドで実行するとします。このメソッドで、Obj
自分自身のポインターを次のように設定するnil
と、本質的に自分自身を削除しますか? (これ以上強力なポインタが残っていないため) 答えはノーだと思いますが、なぜですか? これが機能する場合、それはコーディング方法が悪いのでしょうか (コーディングは良くないと思いますが、実際には悪いのでしょうか?)
4 に答える
コードが適切に設計されている場合、オブジェクトが独自の解放/割り当て解除を引き起こす可能性はほとんどありません。はい、あなたが説明する状況は悪いコーディング慣行を示しており、実際にプログラムがクラッシュする可能性があります。以下に例を示します。
@interface Widget : NSObject
@property (retain) NSMutableArray *array;
@end
@implementation Widget
@synthesize array;
- (id)init
{
self = [super init];
if(self) {
array = [[NSMutableArray alloc] init];
[array addObject:self];
}
return self;
}
- (void)dealloc
{
NSLog(@"Deallocating!");
[array release];
[super dealloc];
}
- (void)removeSelf
{
NSLog(@"%d", [array count]);
[array removeObject:self];
NSLog(@"%d", [array count]);
}
@end
そして、このコードは別のクラスにあります:
Widget *myWidget = [[Widget alloc] init];
[myWidget release]; // WHOOPS!
[myWidget removeSelf];
NSLog in への 2 回目の呼び出しは、その時点で割り当てが解除され、メソッドを呼び出すことができないremoveSelf
ため、EXC_BAD_ACCESS を引き起こします。array
ここには少なくともいくつかの間違いがあります。最終的にクラッシュを引き起こすのは、オブジェクトを作成および使用しているクラスが、使用myWidget
が完了する前にオブジェクトを解放する (removeSelf を呼び出すため) という事実です。この間違いがなければ、コードは正常に実行されます。ただし、保持サイクルが発生するため、MyWidget は最初からそれ自体への強い参照を作成するインスタンス変数を持つべきではありません。誰かがmyWidget
最初に を呼び出さずに解放しようとするとremoveSelf
、何も解放されず、おそらくメモリ リークが発生します。
バックポインターが弱い場合 (クラスがその所有者を所有しようとしないため、そうあるべきです)、配列からストロング ポインターを削除すると、オブジェクトはヒープから削除されます。 . 強力なポインターがない = メモリから削除されます。
これはいつでもテストできます。
削除された状況にクラスをもたらす必要がある場合、ベスト プラクティスは、最初にクラスを保持/自動解放してから、状況を発生させることです。この場合、クラスはメソッドの途中では削除されませんが、その後にのみ削除されます。
方法によっては、悪いコーディング手法であると言えると思います。安全に、またはおそらく安全に行う方法はいくつかあります。
それでは、グローバルがあるとしましょう:
NSMutableArray *GlobalStore;
1 つの方法は、最終的なアクションとして自分自身を削除することです。
- (void) someMethod
{
...
[GlobalStore removeObject:self];
}
これは最終的なアクションであるため、将来の使用はself
なく、おそらくすべてがうまくいくはずです...
他のオプションには、遅延時間 0 で削除をスケジュールすることが含まれます。これは、実行ループで次回起動することを意味します (もちろん、実行ループがある場合にのみ機能しますが、スレッドでは機能しない場合があります)。これは常に安全でなければなりません。
オブジェクトにそれ自体への参照を保持させることもできます。これにより、サイクルが生成され、オブジェクトが存続します。死ぬ準備ができたら、それ自身の参照を無効にすることができます。他の参照がなく、それが最終アクション (または別のオブジェクトによってスケジュールされたアクション) である場合、オブジェクトは死んでいます。