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 在第二行报告了泄漏,“i”旁边的百分比为 %100。

所以我尝试了两件事:

一,我nm用这样的autohrleas标记:

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

nm二,我还尝试在分配后调用 release ,imgInfo->name因此代码如下所示:

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

但是在这两种情况下,当我运行它并调用[imgInfo->name UTF8String].

我错过了什么?

按照 Rob 的回答进行编辑:

这是 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

还有他们:

#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. Instruments 确定了泄漏对象的分配位置,但在这种情况下,此代码可能不是泄漏的来源。你应该:

    • 确保您release使用namedealloc方法RUBEImageInfo;和

    • 另外,如果您要第二次设置,请在将其设置为新对象之前name确保您release是前一个对象。name

  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 
    

    通过使用 setter 访问器方法(即 的“点语法” imgInfo.name),它将处理许多例行内存语义,以释放name可能已引用的任何先前对象,并且它将执行必要的copyor retain。显然,该RUBEImageInfo方法dealloc仍然需要 release name,但至少简化了对象name属性的内存语义。RUBEImageInfo

  3. 由于您使用手动引用计数,我鼓励您研究“静态分析器”(通过从 Xcode 的“产品”菜单中选择“分析”来调用)。Instruments 中的 Leaks 工具会告诉您泄漏了什么,但不会告诉您泄漏发生在哪里;它无法知道;它只能向您显示泄漏对象的分配位置,您必须自己寻找逻辑错误。静态分析器有时可以指出导致泄漏的错误,但更重要的是,向您显示导致泄漏的位置,而不仅仅是泄漏对象最初实例化的位置。在您开始运行 Instruments 之前,您应该从静态分析器中获得一份干净的健康清单。


查看您的代码示例,如果您不打算使用声明的属性(不知道为什么不使用,因为它使生活更轻松,但对每个人来说都是他自己的),我建议您确保初始化所有对象ininitrelease所有这些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 回答