3

読み込み時に人物オブジェクトを作成するテーブルビューがあります

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

人.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

私の UITableView メソッド cellAtRowForIndexPath 内で、各人物オブジェクトを作成し、画像プロパティを次のように割り当てています...

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

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

これを Instruments で実行すると、NSData *data... 行が強調表示され、そこにリークがあることが示されます。

なぜそこに漏れているのですか?

4

3 に答える 3

5

まず、インスタンス変数とプロパティ、および getter/setter の違いを理解する必要があります。

  • インスタンス変数 (ivar) は、オブジェクトに格納される変数です。名前を付けるだけで、メソッド内から ivar にアクセスできます (「userName」など)。
  • プロパティは、オブジェクトへのインターフェースを定義し、情報をオブジェクトに読み書きできるようにします。
  • ゲッター/セッターはそのインターフェースを実装し、バッキング ストレージとして ivar を使用する場合があります

明示的に ([self userName] など) または (同等に) ドット構文 self.userName を使用して、getter/setter を使用してプロパティにアクセスします。これら 2 つの表記法はまったく同じであることに注意してください。次のように、オブジェクトのインターフェースで @property を使用して、プロパティを宣言します (つまり、オブジェクトへのインターフェースを宣言します)。

@property (copy) NSString* userName;

この宣言は、基本的に次のように入力することと同じです。

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

@synthesize を使用して (コンパイラに getter/setter を作成するように指示するだけです)、または自分で実装して (つまり、userName と setUserName のメソッド実装を記述します)、プロパティを実装します。めったに使用されない 3 番目のオプション @dynamic もあります。これは、実行時にメソッドを処理することをコンパイラに通知し、基本的に、それ以外の場合に表示される警告を黙らせるだけです。

次に、メモリ管理ルールを読んで理解する必要があります。わずか 9 つの短いパラグラフです。今すぐ読んでください。お待ちしています。終わり?良い。

さらに、init または dealloc ルーチンで getter/setter を使用しないことを知っておく必要があります。

したがって、初期化ルーチンは次のようになります。

- (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;
}

保持またはコピーを使用して、ivar に保存する各値の所有権を取得することに注意してください。通常、変更可能な文字列への参照を保持したままにする保持ではなく、copy for NSString を使用して、NSMutableStrings を所有する NSStrings に変換します。同じ問題が NSArray/NSDictionary にも当てはまりますが、TwitterHelper は取得したデータを引き渡すつもりであると想定します。

あなたの dealloc は、さまざまな ivar を解放する必要があります。

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

コード内の他の場所では、ivar に直接アクセスするのではなく、self.userName を使用してプロパティにアクセスまたは変更します。

displayName (および同様の画像) をまったく保存しないことを検討するかもしれませんが、userInfo からそれを取得するプロパティ ゲッターを実装するだけであることに注意してください。これを行うには、displayName ivar を削除し、プロパティを次のように変更します。

@property (読み取り専用) NSString *displayName;

@synthesize の displayName を削除し、手動ゲッターを追加します。

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

そしてdeallocでリリースを削除します。

displayName の値を保持/解放する必要がないことに注意してください。受信者が所有していない値を返します。保持したい場合は、受信者がそれをコピー/保持する必要があります。

于 2009-08-13T03:10:10.397 に答える
1

プロパティを作成する場合は、次を使用する必要があります。

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

あなたのinitメッセージではなく

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

selfプレフィックスなしで値を設定しても、copyまたはretainメッセージは呼び出されず、メモリの問題が発生します(必ずしもリークではありません)。

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

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

または、アクセサーを使用したくない場合は、retainまたはcopy取得した値を使用します。例:

image = [[NSURL URLWithString:[userInfo valueForKey:@"profile_image_url"]] retain];
于 2009-08-12T16:30:05.717 に答える
0

Personを呼び出しallocていますが、解放していません。personオブジェクトをリークしました。(セル構成で)

于 2009-08-13T03:25:23.470 に答える