2013-07-14 125 views
2

我正在做我的第一步,在xCode 4.5中找到内存泄漏并使用Leaks工具。我发现了一些问题,似乎解决了这些问题,但是这个问题没有解决。调试目标c使用xCode泄漏的内存泄漏

下面是代码:

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 

泄漏报告在第二行中的泄漏,与旁边的百分比第“i”在100%。

所以,我想两件事情:

一个,标志着我nm像这样autohrleas:

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

两个,我也打过电话发布在nm这是分配给imgInfo->name使代码看起来像后这个:

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

但是在这两种情况下,当我运行它的应用程序崩溃时,并且调用[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 
+1

**永远不要用' - >'来设置或对象检索值。 **这只是摆脱了错误的做法。它很脆弱,打破了封装,而且根本不用。 – bbum

+0

所以@bbum你会怎么做? – Eddy

+0

通过点语法或常规方法语法调用setters/getters。 – bbum

回答

0

一对夫妇的反应:

  1. 仪器标识确定泄漏对象的分配位置,但在这种情况下,此代码可能不是泄漏源。你应该:

    • 确保您releasenameRUBEImageInfodealloc方法;并且

    • 此外,如果您第二次设置name,请确保您之前的对象release已设置为name,然后再将其设置为新对象。如果你使用declared properties,而不是取消引用类的实例变量

  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“点语法”),它将处理大量例程内存语义,释放之前可能引用的任何对象,并且它将执行必要的copyretain。显然,RUBEImageInfo方法dealloc仍然需要发布name,但至少它简化了RUBEImageInfo对象的name属性的内存语义。因为您使用的是手动引用计数,所以我鼓励您调查“静态分析器”(通过从Xcode的“产品”菜单中选择“分析”调用)。乐器中的泄漏工具会告诉你泄漏的是什么,但它不会告诉你泄漏发生在哪里;它无法知道;它只能告诉你泄漏对象的分配位置,你将不得不自己寻找逻辑错误。静态分析器有时会指出会导致泄漏的错误,但更重要的是,可以告诉您泄漏的来源,而不仅仅是最初实例化泄漏对象的位置。在您运行仪器之前,您应该从静态分析仪获得一份干净的健康证书。


看你的代码示例,如果你不打算使用声明的属性(不知道为什么你不会,因为它使生活更轻松,但每一个他自己),我ð建议确保你初始化所有的物体在initrelease所有的人都在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 
+0

谢谢,罗布。我尝试在RUBEImageInfo dealloc方法中释放名称,但泄漏仍然存在。 (并且分析不会报告任何内容。)我编辑了问题以添加相关类。 – Eddy

+0

@Eddy你是否稍后再设置'name'?如果是这样,你应该释放它,就像我修改后的答案中所示。如果你省略了这个'release',乐器会将泄漏的字符串显示回原来实例化了'imgInfo'的地方。如果你没有再次设置'name'实例变量,就像我最终的代码示例中显示的那样,那么你必须有别的东西保留'name'引用的字符串对象。 – Rob

+0

@Eddy顺便说一句,如果你还在泄漏'name',我会暂时在'dealloc'中放置一个断点或NSLog语句,并确保它被调用(如果不是,泄漏的'name'是一个症状一个更广泛的问题,'imgInfo'的泄漏),并且如果它被调用,请检查'[name retainCount]'(在执行'release'之前它应该是'1'... ...如果没有''保留'name'的其他东西)。 – Rob