2009-08-12 11 views
3

私はロードが人物オブジェクトの私のUITableView法cellAtRowForIndexPathインサイドどのようにしてメモリが漏れていますか?

Person.h

#import <UIKit/UIKit.h> 
#import "TwitterHelper.h" 

@interface Person : NSObject { 
    NSDictionary *userInfo; 
    NSURL *image; 
    NSString *userName; 
    NSString *displayName; 
    NSArray *updates; 
} 
/* 
@property (retain) NSString *userName; 
@property (retain) NSString *displayName; 
@property (retain) NSDictionary *userInfo; 
*/ 
@property (nonatomic, copy) NSURL *image; 
@property (retain) NSArray *updates; 

- (id)initWithUserName:userName; 

@end 

Person.m

#import "Person.h" 


@implementation Person 

/* 
@synthesize userName; 
@synthesize displayName; 
@synthesize userInfo; 
*/ 
@synthesize image; 
@synthesize updates; 

- (id)initWithUserName:(NSString *)user{ 

    userName = user; 
    userInfo = [TwitterHelper fetchInfoForUsername:user]; 
    displayName = [userInfo valueForKey:@"name"]; 
    image = [NSURL URLWithString:[userInfo valueForKey:@"profile_image_url"]]; 
    updates = [TwitterHelper fetchTimelineForUsername:userName]; 

    return self; 
} 

- (void)dealloc 
{ 
    /* 
    [userName release]; 
    [displayName release]; 
    [updates release]; 
    [userInfo release]; 
    [image release]; 
    */ 
    [super dealloc]; 
} 

@end 

を作成するときに、私は一人一人のオブジェクトを作成していますことをテーブルビューを持っているし、イメージプロパティを割り当てます。

Person *person = [[Person alloc] initWithUserName:userName]; 

NSData *data = [[NSData alloc] initWithContentsOfURL:person.image]; 
[data release]; 

これをインストゥルメントで実行すると、NSData *データ行がハイライト表示され、そこにリークが表示されます。

なぜそこに漏れていますか?

答えて

1

あなたがプロパティを作成することを選択した場合、あなたが使用する必要があります。あなたのinitメッセージやない

image = [NSURL URLWithString:[userInfo valueForKey:@"profile_image_url"]]; 

self.image = [NSURL URLWithString:[userInfo valueForKey:@"profile_image_url"]]; 

self接頭辞なしで値を設定すると、copyまたはretainを呼び出すことはありませんメッセージが表示され、メモリの問題が発生します(必ずしもリークではありません)。

これは、Instrumentsがあなたを指しているものかもしれません。

(これは明らかに、すべてのプロパティに適用されます!)

を別の方法として、あなたはアクセサを使用しない場合は、取得した後、retainまたはcopy値、例えば:

image = [[NSURL URLWithString:[userInfo valueForKey:@"profile_image_url"]] retain]; 
+0

プロパティを宣言する方法(アトミック、保持、コピーなど)で違いがありますか? – Jason

+0

私はそれが違いを生むと知っているはずですが、私の上記の例では、何をすべきでしょうか? – Jason

+2

いいえ!イニシャライザやdeallocメソッドでは、アクセサー(明示的にまたはドット表記法)を使用しないでください。これらのメソッドでは、直接プロパティアクセス*を使用します。getter/setterを呼び出すと、これらの2つの状況で意図しない(そして不適切な)対処が行われる可能性があります。 ただし、NSURLをコピーする必要があります。 Cocoaのメモリ管理ガイドを再度読んでください。 –

5

まず、あなたはインスタンス変数とプロパティとゲッター/セッターの違いを理解する必要があります。

  • インスタンス変数(ivars)は、オブジェクト に格納されている変数です。あるメソッド内からivarにアクセスするには、単にそれを命名するだけです(例: "userName")。
  • プロパティは、オブジェクトへの インターフェイスを定義し、 情報をオブジェクトに読み取ったり、書き込んだりすることができます。
  • ゲッター/セッターは、そのインターフェイスを実装し、バッキングストレージとしてIVARを使用することができ

あなたは、ゲッター/セッターを使用してプロパティにアクセスする明示的に(例えば、[自己のuserName])または(同等)、ドット構文を使用してself.userName。これらの2つの表記はまったく同じであることに注意してください。このdeclartionはタイピングと本質的に同等である

@property (copy) NSString* userName; 

:あなたは、あなたのオブジェクトのインタフェースで@propertyを使って(つまり、あなたがあなたのオブジェクトへのインターフェイスを宣言)のようなものをプロパティを宣言

- (NSString*) userName; 
- (void) setUserName: (NSString*) theUserName; 

@synthesize(単にコンパイラにゲッター/セッターを書くよう指示する)か、自分で実装する(つまり、userNameとsetUserNameのメソッド実装を書く)かのどちらかでプロパティを実装します。まれに使用される3番目のオプション@dynamicもあります。このオプションは、実行時にメソッドを処理するコンパイラに指示します。

次に、memory management rulesを読んで理解する必要があります。その唯一の9つの短い段落は、今それを読んで行く、私は待っています。終わった?良い。

また、getter/setterをinitルーチンまたはdeallocルーチンで使用しないでください。あなたが保持またはコピーとIVARに格納各値の所有権を取得

- (id)initWithUserName:(NSString *)user{ 
    userName = [user copy]; 
    userInfo = [[TwitterHelper fetchInfoForUsername:user] retain]; 
    displayName = [[userInfo valueForKey:@"name"] copy]; 
    image = [[NSURL URLWithString:[userInfo valueForKey:@"profile_image_url"]] copy]; 
    updates = [[TwitterHelper fetchTimelineForUsername:userName] retain]; 
    return self; 
} 

注:

だからあなたのinitルーチンは、次のようになります。一般的には、NSStringをコピーしてNSMutableStringsを自分が所有するNSStringに変換します。保持するのではなく、おそらく変更可能な文字列への参照を保持します。同じ問題がNSArray/NSDictionaryに当てはまりますが、私たちはTwitterHelperがフェッチされたデータを引き渡すつもりであると仮定します。

- (void)dealloc 
{ 
    [userName release]; 
    [displayName release]; 
    [updates release]; 
    [userInfo release]; 
    [image release]; 
    [super dealloc]; 
} 

どこでも他にあなたのコードであなたがアクセスしたり、変更するプロパティを、直接ではなくアイバーズにアクセスするためにself.userNameを使用します。

あなたのdeallocは、様々なアイバーズを解放する必要があります。

displayName(および同様のイメージ)をまったく格納しないでくださいが、userInfoから取得するプロパティゲッターを実装するだけでよいことに注意してください。これを行うには、displayName ivarを削除し、プロパティを次のように変更します。

@property(readonly)NSString * displayName;

は@synthesizeののdisplayNameを削除し、手動ゲッター追加:

- (NSString*) displayName 
{ 
    return [userInfo valueForKey:@"name"]; 
} 

とのdeallocでのリリースを削除します。

displayNameに値を保持/解放する必要はありません。受信者を所有していない値を返します。保持したい場合は、コピー/保持する必要があります。

+0

これは素晴らしい答えです。ありがとうございます。残っているのは、@propertyと@synthesize宣言の理解だけです。あなたはその地域にいくつかの洞察力を提供できますか?再度、感謝します。 – Jason

0

あなたはallocに人を呼び出していますが、公開していません。あなたはpersonオブジェクトを漏らしました。 (セル構成で)

+0

申し訳ありませんが、提供されたコードから[人のリリース]メソッドを削除しました。それはそこにあります。また、それが当てはまる場合、Instrumentsは私にその行を指摘しないでしょうか? – Jason

+0

ああ、そうです。 Clang Static Analyzerでコードを実行しようとしましたか?以前に使ったことがない人は、本質的にグラフィカルなフロントエンド(そしてより優秀な)である "AnalysisTool"のためのグーグルリングを試みて、あなたのプロジェクトを分析できるようにしてください。それは漏れを見つけるだけでなく、それらを段階的にあなたに示します。それは素晴らしいツールです。 – jbrennan

関連する問題