0

ビューに追加した後、サブビューのretainCountをチェックしています。コードは次のとおりです。

- (void) loadView{
    //...
    toolbar = [[UIToolbar alloc] initWithFrame:nil];
    [[self view] addSubView:toolbar];
}

- (void) dealloc{
    NSLog(@"count=%d", [toolbar retainCount]);   // count=2
    [toolbar removeFromSuperView];
    NSLog(@"count=%d", [toolbar retainCount]);   // count=1
    [toolbar release]
    NSLog(@"count=%d", [toolbar retainCount]);   // count=1
    toolbar = nil;
    NSLog(@"count=%d", [toolbar retainCount]);   // count=0
}

dealloc{} のこのコードから、いくつか質問があります。

1、ツール バーの最初のログの保持カウントは 2 です。初期化後にツール バーがセルフ ビューに追加されるため、保持カウントは 2 になります。

2、ツールバーの removeFromSuperView の後、retainCount は 1 になります。

3、ツールバーが release メソッドを呼び出した後、retainCount は 1 のままで、0 になることはありません。 0.

4, nil に設定されたツールバーを呼び出すと、retainCount は 0 になります。このログは役に立ちません。

私の質問は次のとおりです。

a) ツールバーは removeFromSuperView とリリース API を呼び出しますが、結果は同じで、ツールバーのretainCount は 1 になるだけです。そのため、それぞれを使用するだけでコードをテストすると、結果は同じになります。では、ユーザーはそれぞれ 1 つの API しか呼び出すことができなくても問題ないと結論付けることができますか?

b)Apple ドキュメントから、セルフ ビューにサブビューが追加され、セルフ ビューはツールバー ハンドルのままであるため、dealloc メソッドでは、viewDidUnload が呼び出されない場合、ツールバーのretainCount を 0 に減らすことはできません。メモリが不足している場合、システムは不要なビューを減らして viewDidUnload メソッドを呼び出し、ツールバーのretainCountを自動的に0に減らします。したがって、deallocメソッドでツールバーをnilに設定する必要があります。ツールバーを nil に設定すると混乱します。viewDidUnload メソッドが呼び出されると、ツールバーが縮小されますか? メモリリークはありますか?

どうも。

4

1 に答える 1

2

まず、コードが実際のコードを反映している場合、deallocメソッドには大きな問題があります。

- (void) dealloc{
   [toolbar removeFromSuperView];
   [toolbar release]
   toolbar = nil;
}

あなたは電話していません[super dealloc]。[super dealloc] を呼び出さないことにより、self.view解放されることはありません (最終的に解放されます)。

これにより、メモリリークが修正されます(少なくとも部分的に):

- (void) dealloc{
    [toolbar release];
    [super dealloc];
}

の呼び出しを削除したことに気付くと思いますがremoveFromSuperView、これは が実際に割り当て解除されたときに自動的に行われるためself.view、自分で行う必要はありません。いずれにせよ、呼び出しremoveFromSuperViewても問題はありません。

toolbarあなたの質問について、私はあなたの財産が次のように宣言されていると仮定しますretain(あなたが提出したコードに基づいて、それは私にとって最も感覚的な仮説です)。

toolbarプロパティの子供である場合retain、新しく作成されたビューをそれに割り当てる正しい方法は次のとおりです。

 toolbar = [[[UIToolbar alloc] initWithFrame:nil] autorelease];

注意してくださいautorelease; そこにない場合は、保持/解放呼び出しが損なわれます。releaseこれは、最初に呼び出してから、 deallocnilのプロパティを呼び出す必要があることを説明している可能性があります。

- (void)dealloc {
 ...
    [toolbar release]
    toolbar = nil;
 ....
}

そのようにすることで、toolbar2回リリースしています。しかし、保持プロパティに割り当てるときに使用しなかったautoreleaseため、正しい結果が得られます。

a) ツールバーは removeFromSuperView とリリース API を呼び出しますが、結果は同じで、ツールバーのretainCount は 1 になるだけです。そのため、それぞれを使用するだけでコードをテストすると、結果は同じです。では、ユーザーはそれぞれ 1 つの API しか呼び出すことができなくても問題ないと結論付けることができますか?

removeFromSuperView私が言ったように、サブビューを解放するためにdealloc直接呼び出す必要はありませself.viewん。周囲を維持したままサブビューを削除したい場合は別の問題ですsuperview(ラベルを表示してから削除すると想像してください)。この場合、両方を呼び出す必要があります。そうしないと、リークが発生します。

b)Apple ドキュメントから、セルフ ビューにサブビューが追加され、セルフ ビューはツールバー ハンドルのままであるため、dealloc メソッドでは、viewDidUnload が呼び出されない場合、ツールバーのretainCount を 0 に減らすことはできません。メモリが不足している場合、システムは不要なビューを減らして viewDidUnload メソッドを呼び出し、ツールバーのretainCountを自動的に0に減らします。したがって、deallocメソッドでツールバーをnilに設定する必要があります。ツールバーを nil に設定すると混乱します。viewDidUnload メソッドが呼び出されると、ツールバーが縮小されますか? メモリリークはありますか?

私があなたの疑いを正しく理解していれば、要点は、toolbarプロパティをnilinviewDidUnloadに送信した場合、このメソッドが呼び出されたとき (ビューを明示的に削除したとき、またはメモリ警告が発行されたとき)、サブビューが正しく破棄されるということです。deallocfor your controller が今後呼び出される場合、プロパティには既にnil値があるため、それを解放しても効果はありません (ただし、 で既に解放されているため、問題ありませんviewDidUnload)。

一方、プロパティを解放しないとviewDidUnload、メモリ警告の後にビューが再度表示された場合にloadView/viewDidLoadが再度呼び出されます。ただし、この場合、ツールバーのサブビューを作成し、その参照をtoolbarプロパティに割り当てると (それがretain親切であると仮定して)、古いオブジェクトが自動的に解放されるため、メモリ リークは発生しません。何が起こるかというと、おそらくできるよりも多くのメモリを使用しているということです (ツールバーは が再度作成されるまで割り当て解除されないためself.view)。

于 2012-06-14T07:57:06.837 に答える