iPhoneでの予期しないシングルトンクラスの動作、何か間違っていますか?
-
05-07-2019 - |
質問
次のようにシングルトンクラスを実装しています:
static Singleton* _singletonInstance;
@implementation Singleton
+(void)initialize
{
_singletonInstance = [[Singleton alloc] init];
}
+(Singleton*)instance
{
return(_singletonInstance);
}
initializeは、誰かが最初にインスタンスを呼び出すときにのみ呼び出されます。次に、いくつかのインスタンス変数を設定するために呼び出すことができるメソッドがあります。したがって、最終的には次のようになります。
_singleton = [Singleton instance];
[_singleton setupWithParams: blah];
オブジェクト内でこのシングルトンのインスタンスを取得すると、初めて正常に動作します。ただし、シングルトンのインスタンスが必要なオブジェクトの割り当てを解除して新しいコピーを作成した後、セットアップ関数を呼び出そうとするとBAD ACCESSエラーが発生します。
テストを行うために、セットアップコールを行う前にインスタンスのアドレスを出力し、両方が同じアドレスを報告しますが、BAD ACCESSコールのエラーログをチェックすると、まったく異なるメモリアドレスがリストされます。
このインスタンスへのポインタを印刷するとうまく見えるように見える理由はありますが、呼び出しを行うと、ランダムなデータを指しているように見えますか?
解決
ポインタ値は以前は有効だったように見えますが、メモリが解放された可能性が高いため、指す値はランダムデータのように見えます。
上記の [[Singleton alloc] init]
で参照を1つ取得しましたが、実行中の別の場所に release
がありますか?あなたのコードが参照を取得したことはないにせよ、あなたのコードは instance
を呼び出し、その後 release
を呼び出しているに違いありません。とにかく、それはシングルトンには必要ないはずです。ただの推測...
他のヒント
どこか_singletonInstanceの割り当てを解除していますか?
私はもっと複雑ですが、非常に安定したバージョンのシングルトンテンプレートを使用しています(ブランドン" Quazie" Kwaselowブログ):
static SampleSingleton *sharedSampleSingletonDelegate = nil;
+ (SampleSingleton *)sharedInstance {
@synchronized(self) {
if (sharedSampleSingletonDelegate == nil) {
[[self alloc] init]; // assignment not done here
}
}
return sharedSampleSingletonDelegate;
}
+ (id)allocWithZone:(NSZone *)zone {
@synchronized(self) {
if (sharedSampleSingletonDelegate == nil) {
sharedSampleSingletonDelegate = [super allocWithZone:zone];
// assignment and return on first allocation
return sharedSampleSingletonDelegate;
}
}
// on subsequent allocation attempts return nil
return nil;
}
- (id)copyWithZone:(NSZone *)zone
{
return self;
}
- (id)retain {
return self;
}
- (unsigned)retainCount {
return UINT_MAX; // denotes an object that cannot be released
}
- (void)release {
//do nothing
}
- (id)autorelease {
return self;
}
Valeriiのコードはシングルトンの実装に適していますが、問題はほとんどの場合、[シングルトンインスタンス]を呼び出すコードが、実際に保持を使用して所有権を取得せずに所有権を持っているように動作し、後でリリースすることです。
バグを探し、メモリ管理を読みますルール。
また、Xcodeでは、 NSZombieEnabledを有効にすると、コンソールが表示されますオブジェクトが解放された後にメッセージを送ってください。