iPhoneのメモリ管理とリリース
-
03-07-2019 - |
質問
私がよく目にする一般的な慣行は次のとおりです(非常に人気のあるiPhone開発者の本を含む)
.hファイル内:
@interface SomeViewController : UIViewController
{
UIImageView *imgView;
}
.mファイルのどこか:
imgView = [[UIImageView alloc] initWithFrame:[[UIScreen mainScreen]
applicationFrame]];
[imgView setImage:[UIImage imageNamed:@"someimage.png"]];
[self addSubview:imgView];
[imgView release];
その後、これが表示されます...
- (void) dealloc
{
[imgView release];
[super dealloc];
}
imgViewには対応するallocとリリースがあるため、deallocでのimgViewのリリースは必要ですか?
addSubview呼び出しによって保持されるimgViewはどこにありますか?
解決
はい、そのコードには問題があります。 imgViewのリリースが早すぎるため、まれにクラッシュが発生する可能性があります、オブジェクトを保持せずにインスタンス変数に保存します。通常、メモリ管理は間違った方法で行われます。
これを行う正しい方法の1つは次のとおりです。
@interface SomeViewController : UIViewController
{
UIImageView *imgView;
}
@property (nonatomic, retain) UIImageView *imgView;
そして実装;
@synthesize imgView;
モジュール内のどこか:
//Create a new image view object and store it in a local variable (retain count 1)
UIImageView *newImgView = [[UIImageView alloc] initWithFrame:self.view.bounds];
newImgView.image = [UIImage imageNamed:@"someimage.png"];
//Use our property to store our new image view as an instance variable,
//if an old value of imgView exists, it will be released by generated method,
//and our newImgView gets retained (retain count 2)
self.imgView = newImgView;
//Release local variable, since the new UIImageView is safely stored in the
//imgView instance variable. (retain count 1)
[newImgView release];
//Add the new imgView to main view, it's retain count will be incremented,
//and the UIImageView will remain in memory until it is released by both the
//main view and this controller. (retain count 2)
[self.view addSubview:self.imgView];
そして、deallocは同じままです:
- (void) dealloc
{
[imgView release];
[super dealloc];
}
他のヒント
コードが正しくありません。割り当てが解除されると、 imgView
が解放されます。
.mファイルでは、次のことができます。
-
alloc
it->あなたがそれを所有している - サブビューとして追加->あなたと UIViewが所有している
-
release
it->あなたはそれを所有していない
dealloc
では、上記の手順3で確立したように、所有者ではないにもかかわらずimgViewを release
します。 [super dealloc]
を呼び出すと、ビューはすべてのサブビューを解放し、例外が発生することを想像します。
imgView
のivarを保持したい場合は、サブビューとして追加した後に release
を呼び出さないでください。 dealloc
も同じです。そうすれば、 imgView
がビュー階層からある時点で削除されたとしても、それへの有効な参照が残っています。
コードが間違っています。deallocが呼び出されたときにinitメソッドで解放しないでください(ivarとして保持する場合は、ポインタを必要としない限り、その必要はありません) addSubview:がビューを保持するため、他の場所で)。
実際にクラッシュしない理由は、(addSubview:の呼び出しから)スーパークラスによってまだ保持されているためだと思います。ビューはおそらく、直後に割り当てが解除されるとスーパービューから自身を削除するため、 [super dealloc]
が呼び出されてもオーバーリリースされません。それは私の予感です、リースで。
initのリリースは正しくありません。
「一般的な慣行」に言及しました名前のない本。 Appleの標準的な例を参照することをお勧めします。ViewTransitionsは、この場合の良い例です(起動する2つのビュー;)
http://developer.apple.com/iphone/library /samplecode/ViewTransitions/index.html
(コメントを追加するほどの評判はまだありません。)
@bentford:間違っている場合は修正してください。ただし、imgViewプロパティの合成セッターを使用するには、" self.imgView"を使用する必要があると思います:
self.imgView = [[UIImageView alloc] initWithFrame:[[UIScreen mainScreen]
自己を持っていない場合、それは単にivarを使用しているだけであり、追加の保持を取得していません。
基本的な答えは、サンプルコードに [imgView release]
が1つしかないことです( addSubviewの後かdeallocにあるか)。ただし、 dealloc
から [imgView release]
を削除し、 addSubview
の後に残します。
iPhoneには問題があります。 didReceiveMemoryWarning
を使用すると、オブジェクト(ビュー全体を含む)を下から解放できます。アプリケーション全体の保持セットがあり、メモリを尊重しない場合は、アプリケーションが強制終了されるだけです。
良い例:
ネストされた3つのビューのセットを考える場合、ビュー1->表示2->表示3。
次に、「 viewDidLoad
」および「 viewDidUnload
」の呼び出しを検討します。ユーザーが現在「ビュー3」にいる場合、View1がアンロードされている可能性があります。これが厄介な場所です。
viewDidLoad
内でオブジェクトを割り当て、サブビューに追加した後に解放しなかった場合、view1がアンロードされてもオブジェクトは解放されませんが、view1はまだアンロードされます。
viewDidLoad
が再度実行され、コードが再度実行されますが、オブジェクトのインスタンス化は1つではなく2つになりました。 1つのオブジェクトは、以前にアンロードされたビューを持つどこにも存在せず、新しいオブジェクトは現在表示されているビュー用になります。すすぎ、泡立て、繰り返します。メモリリークによりアプリケーションがクラッシュします。
この例では、指定されたコードブロックが揮発性であり、再度実行される可能性がある場合(メモリまたはアンロードされたビュー)、 [imgView release ];
deallocからaddSubViewの後に残します。
基本的な保持/リリースの概念に関するリンクは次のとおりです。 http://www.otierney.net/objective-c.html#retain