2

xCode 4.5 でメモリ リークを見つけ、Leaks インストゥルメントを使用するための最初のステップを実行しています。いくつかの問題を見つけて修正したように見えましたが、これは私にはわかりません。

コードは次のとおりです。

RUBEImageInfo* imgInfo = [[[RUBEImageInfo alloc] init] autorelease];
NSString *nm = [NSString stringWithUTF8String:img->name.c_str()];
imgInfo->name = nm;
[imgInfo->name retain]; // I'm using it outside of this method 

Leaks は 2 行目にリークを報告します。「i」の横のパーセンテージは %100 です。

そこで、次の 2 つのことを試しました。

nm1つは、次のようにautohrleasでマークしました。

NSString *nm = [[NSString stringWithUTF8String:img->name.c_str()] autorelease];

nm2 つ目は、割り当て後にrelease を呼び出してみたimgInfo->nameので、コードは次のようになります。

imgInfo->name = nm; 
[imgInfo->name retain]; 
[nm release]; 

しかし、どちらの場合も、実行するとアプリが BAD_ACCESS でクラッシュし、[imgInfo->name UTF8String].

私は何が欠けていますか?

ロブの答えに続いて編集:

これは RUBEImageInfo クラスです。

#import "cocos2d.h"

@interface RUBEImageInfo : NSObject {

@public CCSprite* sprite;               // the image
@public NSString* name;                 // the file the image was loaded from
@public class b2Body* body;             // the body this image is attached to (can be NULL)
@public float scale;                    // a scale of 1 means the image is 1 physics unit high
@public float angle;                    // 'local angle' - relative to the angle of the body
@public CGPoint center;                 // 'local center' - relative to the position of the body
@public float opacity;                  // 0 - 1
@public bool flip;                      // horizontal flip
@public int colorTint[4];               // 0 - 255 RGBA values
}

@end

そして.m:

#import "RUBEImageInfo.h"

@implementation RUBEImageInfo

// Nothing much to see here. Just make sure the body starts as NULL.
-(id)init
{
    if( (self=[super init])) {
        body = NULL;
}
return self;
}

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

@end
4

1 に答える 1

0

いくつかの反応:

  1. 計測器は、リークしたオブジェクトが割り当てられた場所を特定しましたが、この場合、このコードはリークの原因ではない可能性があります。あなたがすべき:

    • releaseの方法であなたnameを確認してください。とdeallocRUBEImageInfo

    • また、2 回目に設定する場合は、新しいオブジェクトに設定する前に、前のオブジェクトnameを確認してください。releasename

  2. クラス インスタンス変数を逆参照するのではなく、宣言されたプロパティを使用すると、作業がはるかに簡単になります。たとえば、次のようnameに宣言された場合:

    @property (nonatomic, copy) NSString *name; // you could use `retain`, too, but `copy` is safer when dealing with strings
    

    次に、nameプロパティを次のように設定します。

    RUBEImageInfo* imgInfo = [[[RUBEImageInfo alloc] init] autorelease];
    NSString *nm = [NSString stringWithUTF8String:img->name.c_str()];
    imgInfo.name = nm;
    // this is no longer needed as the `name` setter will take care of memory semantics
    // [imgInfo->name retain]; // I'm using it outside of this method 
    

    セッター アクセサー メソッド (つまり、 の「ドット構文」imgInfo.name) を使用することにより、参照された可能性のある以前のオブジェクトを解放するための多くのルーチン メモリ セマンティクスをname処理し、必要なcopyorを実行しretainます。明らかに、このRUBEImageInfoメソッドdeallocは を解放する必要がありますnameが、少なくともオブジェクトのnameプロパティのメモリ セマンティクスが単純化されRUBEImageInfoます。

  3. 手動の参照カウントを使用しているため、「静的アナライザー」(Xcode の「製品」メニューから「分析」を選択して起動) を調査することをお勧めします。Instruments の Leaks ツールは何がリークしたかを教えてくれますが、リークがどこで起こったかは教えてくれません。それを知る方法はありません。リークされたオブジェクトが割り当てられた場所を表示することしかできず、論理エラーを自分で探し出す必要があります。静的アナライザーは、リークにつながるエラーを指摘することがありますが、さらに重要なことは、リークしたオブジェクトが最初にインスタンス化された場所だけでなく、リークが発生した場所を示すことです。わざわざ Instruments を実行する前に、静的アナライザーからクリーンな状態を取得する必要があります。


あなたのコードサンプルを見て、宣言されたプロパティを使用しない場合(なぜそうしないのか分かりません。なぜなら、それは人生を楽にするからですが、それぞれに独自のものです)、すべてのオブジェクトを確実に初期化することをお勧めしますinitおよびreleaseそれらすべてのdealloc:

@implementation RUBEImageInfo

-(id)init
{
    if ((self=[super init])) {
        body = NULL;
        name = nil;
        sprite = nil;
        // I might initialize other class instance variables here, too, but that's up to you
    }
    return self;
}

-(void) dealloc {
    [name release];
    // shouldn't you release `body` and `sprite`, too?
    [super dealloc];
}

@end

次に、インスタンス変数を設定するコードは、新しいオブジェクトを設定する前に、前のオブジェクトnameを確認します。releaseしたがって、最初のインスタンス化は次のようになります。

RUBEImageInfo* imgInfo = [[[RUBEImageInfo alloc] init] autorelease];
NSString *nm = [NSString stringWithUTF8String:img->name.c_str()];
imgInfo->name = [nm retain]; // retain the new object

ただし、後で更新する場合は、次のことを行う必要があります。

NSString *nm = [NSString stringWithUTF8String:someNewImg->name.c_str()];
[imageInfo->name release];   // release the old one
imgInfo->name = [nm retain]; // retain the new object
于 2013-07-14T13:16:59.977 に答える