2

みなさん、11月おめでとうございます。

さて、私は自分のプロジェクトでXcode Buildと分析を試しましたが、いくつかの異常なリークが見られましたが、ObjectiveCの知識では完全には受け入れられませんでした。

そこで、テストプロジェクトを立ち上げて、ここで質問することにしました。

MemoryTestController.h

@interface MemoryTestController : UIViewController{
  UIImageView *tstImageView;
}
@property(nonatomic,retain) UIImageView *tstImageView;
@end

MemoryTestController.m

@implementation MemoryTestController
@synthesize tstImageView;

- (void)viewDidLoad{
  [super viewDidLoad];

  self.tstImageView  = [[UIImageView alloc] //<==This object is leaking
                           initWithFrame:<SomeFrame>]; 
  self.tstImageView.image = [UIImage imageNamed:@"SomeImage.png"];
  [self.view addSubview:tstImageView];
  [tstImageView release];
}

-(void)dealloc{
  [tstImageView release];
  [super dealloc];
}
@end

ビルドして分析しようとすると、clangstaticanalyzerは言います

行xxでのオブジェクトの潜在的なリーク

そして犯人のラインは

self.tstImageView  = [[UIImageView alloc]initWithFrame:<SomeFrame>];

割り当て/保持するたびに1回リリースすると思います。私は何かが足りないのですか、それとも静的アナライザーにいくつかのバグがありますか?

編集:そこに漏れはありますか?

さて、私は楽器のリークツールを使用して上記のプロジェクトを実行しました..何度も試してもリークは表示されませんでした..誰を信じるべきですか?静的分析器またはリーク機器?

4

2 に答える 2

5

あなたの問題はあなたがそれをどのように解放するかです:

- (void)viewDidLoad{
  [super viewDidLoad];

  self.tstImageView  = [[UIImageView alloc] //<==This object is leaking
                           initWithFrame:<SomeFrame>]; 
  self.tstImageView.image = [UIImage imageNamed:@"SomeImage.png"];
  [self.view addSubview:tstImageView];
  [tstImageView release]; // << here
}

あなたはこのようにそれをするべきです:

- (void)viewDidLoad{
  [super viewDidLoad];

  UIImageView * imageView  = [[UIImageView alloc] initWithFrame:<SomeFrame>]; 
  imageView.image = [UIImage imageNamed:@"SomeImage.png"];
  self.tstImageView  = imageView;
  [imageView release];
  [self.view addSubview:self.tstImageView];
}

変数が設定したものと同一であると想定できないため、チェッカーは正しいです。したがって、OPで使用するフォームは、ivarにメッセージをリリースするまでに、ivarの値が割り当てられた値ではない可能性があるため、参照カウントの不均衡を引き起こす可能性があります。

これらのケースはUIImageView、プログラムのコンテキストではほとんど発生しない可能性がありますが、これらの例は、チェッカーがobject->ivarアソシエーションが信頼されないと想定する理由についてのアイデアを提供するはずです。

画像ビューの作成とivarを介してそれを解放するメッセージの間に、次のことがあります。

  self.tstImageView  = [[UIImageView alloc] initWithFrame:<SomeFrame>]; 
  self.tstImageView.image = [UIImage imageNamed:@"SomeImage.png"];
  [self.view addSubview:tstImageView];

1)セッターを介した画像ビューの割り当て2)ゲッターを介した画像ビューへのアクセス3)self.viewに追加する場合のivarへの直接アクセス

  • セッターは、コピーされた値またはキャッシュされた値を使用した可能性があります。UIImageView悪い例ですが、チェッカーは型が一般的にどのように渡されるかを知りません-たとえ渡されたとしても、(時には)安全でない仮定をします。

最も簡単な例は次のとおりです。

- (void)setName:(NSString *)inName {
  NSString * prev = name;
  if (inName == prev) return;
  if (0 == [inName count]) name = @"";
  else name = [inName copy];
  [prev release];
}
  • ivarが保持する値は、その間に変更される可能性があります。この場合、問題になる可能性は低いですが、サブビューとして画像ビューを追加するとself、サブビューを追加したり、渡した画像ビューを置き換えたり削除したりするプロセス/効果がコールバックされて変更される可能性があるとします。その場合、渡した可変ビューがリークし、それが置き換えられたビューに負の不均衡が生じます。

どちらもあなたの例では起こりそうにありませんが、実際のプログラムでは起こります。チェッカーはプロパティではなく、局所性に基づいて正しく評価しています(チェッカーはメソッド呼び出し内で起こることの多くを想定できません)。また、この場合、1つの優れた慣用的なスタイルを奨励します。

編集:そこに漏れはありますか?

さて、私は楽器のリークツールを使用して上記のプロジェクトを実行しました..何度も試してもリークは表示されませんでした..誰を信じるべきですか?静的分析器またはリーク機器?

静的アナライザーは、それに続く参照/割り当てが正しく保持/解放されることを保証できないため、潜在的なリークがあると言います。参照カウントが正しいことを保証できます。プログラムを私の例で書いたように変更することで、静的アナライザーを喜ばせてください。

あなたがそれを書いた方法は、アナライザーが参照に従うことを不可能にしました。

リークやゾンビがなければ、リークはありません。しかし、解決策は簡単に修正できます。プログラムには、開発中に変更する方法があります。私が投稿したフォームを使用する方がはるかに簡単なので、ツールセットとプログラムが正しいことを確認するのが簡単です。静的アナライザーは常に正しいとは限りませんが、静的分析は非常に役立つため、プログラムを調整して満足させる必要があります。私が投稿したプログラムは、人間にとっても理解しやすく、正しいことを確認するのにも役立ちます。

于 2011-11-03T06:24:45.467 に答える
1

このようにretainでプロパティを宣言すると

@property(nonatomic,retain) UIImageView *tstImageView;

プロパティに割り当てるときにretainCountを増やすセッターが追加されます。以下のようにすると、作成したオブジェクトにはすでにretainCount==1があります

self.tstImageView  = [[UIImageView alloc] 
                           initWithFrame:<SomeFrame>];

したがって、tstImageViewオブジェクトのretainCountには2があります。

代わりに行う

UIImageView* view = [[UIImageView alloc] initWithFrame:<SomeFrame>];
self.tstImageView  = view;
[view release];

次に、リリースしたときのリークとは関係ありませんが、代わりに次のように記述します

self.tstImageView = nil;

セッターがretainCountを適切に設定するためです

于 2011-11-03T06:24:17.397 に答える