Objective c I’;如果已将我的属性设置为“保留”,即使设置为“自动释放”,我是否应该释放它?

Objective c I’;如果已将我的属性设置为“保留”,即使设置为“自动释放”,我是否应该释放它?,objective-c,memory-management,cocos2d-iphone,retain,Objective C,Memory Management,Cocos2d Iphone,Retain,假设我们有一些代码如下所示: @interface SomeClass : NSObject @property (nonatomic, retain) NSString *someString; @end @implementation SomeClass @synthesize someString; -(id)init { if (self=[super init]) { someString = [NSString stringWithString:@"some

假设我们有一些代码如下所示:

@interface SomeClass : NSObject
@property (nonatomic, retain) NSString *someString;
@end

@implementation SomeClass
@synthesize someString;
-(id)init {
    if (self=[super init]) {
        someString = [NSString stringWithString:@"some string"];
    }
    return self;
}
@end
@interface SomeLayer : CCLayer
@property (nonatomic, retain) CCSprite *someSprite;
@end

@implementation SomeLayer
@synthesize someSprite;
-(id)init {
    if (self=[super init]) {
        someSprite = [CCSprite spriteWithFile:@"SomeFile.png"];
        [self addChild:someSprite];
    }
    return self;
}
@end
即使
SomeClass
的dealloc方法中的
someString
设置为自动释放,并且我从未在
init
方法中实际保留它,我是否应该释放
someString
属性?如果是这样,我只需在
-release
方法中的
[someString release]
之前添加
[super dealoc]
。对吗

现在我面临的真正问题是,在使用Cocos2D时,我遇到了一个矛盾的情况。我的代码如下所示:

@interface SomeClass : NSObject
@property (nonatomic, retain) NSString *someString;
@end

@implementation SomeClass
@synthesize someString;
-(id)init {
    if (self=[super init]) {
        someString = [NSString stringWithString:@"some string"];
    }
    return self;
}
@end
@interface SomeLayer : CCLayer
@property (nonatomic, retain) CCSprite *someSprite;
@end

@implementation SomeLayer
@synthesize someSprite;
-(id)init {
    if (self=[super init]) {
        someSprite = [CCSprite spriteWithFile:@"SomeFile.png"];
        [self addChild:someSprite];
    }
    return self;
}
@end
现在,我在我的图层
SomeLayer
中添加了
someSprite
。那么,我应该做些什么来确保这里没有内存泄漏呢?我可以想到以下几点:

  • 显然,我想在
    SomeLayer
    -dealoc
    方法中调用
    [someSprite release]
    。但是它在
    [super dealoc]
    中为我提供了
    EXC\u BAD\u访问权限(下一行)。很可能是因为我没有删除子类,而超类试图访问我刚刚发布的子类
  • 我在
    -dealloc
    方法中调用
    [self-removeChild:someSprite cleanup:YES]
    ,这将删除子项并释放它。因此,我不需要跟进
    [someSprite release]
    。但是,超类
    CCNode
    -dealoc
    方法已经为我完成了所有这些
  • 我什么也不做。我根本不会重写
    -dealoc
    方法。好吧,这似乎很有效,但它与“如果你保留了某些东西,你应该释放它”的说法相矛盾
  • 任何关于为什么我必须在案例一中释放对象以及为什么不在案例二的早期阶段释放对象的帮助都有助于从长远来看节省大量与内存相关的问题

    谢谢

    这是错误的。您正在保留一个指向即将消失的自动释放对象的指针,当您尝试使用
    someString
    指针时,会发生不好的事情。您应该使用访问器(
    [self-setSomeString:…]
    ),保留自动删除的值(
    someString=[…retain]
    ),或者使用返回保留值的方法(
    someString=[[NSString alloc]init…])

    在您的实际用例中,您应该对sprite执行相同的操作,因为您过度释放了sprite,所以您将获得
    EXC\u BAD\u访问
    :您调用
    release
    ,但从未保留该值。读这本书,从长远来看,你会省去很多麻烦

    顺便说一下,我认为您的主要问题是您认为对
    someString
    变量的简单赋值会保留赋值。事实并非如此(更准确地说,没有弧也不行)。对实例变量的赋值就是一个普通赋值。如果你想通过访问器,你必须发送一条消息(
    [self-setSomeString:…]
    )或使用点符号(
    self.someString=…

    这是错误的。您正在保留一个指向即将消失的自动释放对象的指针,当您尝试使用
    someString
    指针时,会发生不好的事情。您应该使用访问器(
    [self-setSomeString:…]
    ),保留自动删除的值(
    someString=[…retain]
    ),或者使用返回保留值的方法(
    someString=[[NSString alloc]init…])

    在您的实际用例中,您应该对sprite执行相同的操作,因为您过度释放了sprite,所以您将获得
    EXC\u BAD\u访问
    :您调用
    release
    ,但从未保留该值。读这本书,从长远来看,你会省去很多麻烦


    顺便说一下,我认为您的主要问题是您认为对
    someString
    变量的简单赋值会保留赋值。事实并非如此(更准确地说,没有弧也不行)。对实例变量的赋值就是一个普通赋值。如果你想通过访问器,你必须发送一条消息(
    [self-setSomeString:…]
    )或使用点符号(
    self.someString=…
    )。

    你只需要释放你显式分配的对象。您给出的示例均未分配,因此它们将自动删除。如果要将自动释放的对象保留很长一段时间,则需要保留它,然后才需要释放该对象

    此外,如果您有属性,则应在
    viewDidUnload


    self.someString=nil

    您只需释放显式分配的对象。您给出的示例均未分配,因此它们将自动删除。如果要将自动释放的对象保留很长一段时间,则需要保留它,然后才需要释放该对象

    此外,如果您有属性,则应在
    viewDidUnload


    self.someString=nil

    您确实需要读取内存


    有四条规则中的两条

    • 您可以使用retain获得对象的所有权
    • 当您不再需要它时,必须放弃您所拥有的对象的所有权
    当您将属性声明为
    retain
    时,您应该调用
    release
    以获取适当的变量。在您的情况下,您的dealloc应该看起来

    - (void)dealloc
        [someSprite release];
        [super dealloc];
    }
    

    看看这个代码

     if (self=[super init]) {
            someSprite = [CCSprite spriteWithFile:@"SomeFile.png"]; // here you assign pointer to new object
            [self addChild:someSprite]; // all right, you can use newly created object in this scope
        }
     // but here that object can be deleted from memory and someSprite can points to nothing
    
    为了避免这种情况,您需要保留新创建的精灵

    someSprite = [[CCSprite spriteWithFile:@"SomeFile.png"] retain];
    

    你真的需要阅读记忆


    有四条规则中的两条

    • 您可以使用retain获得对象的所有权
    • 当您不再需要它时,必须放弃您所拥有的对象的所有权
    当您将属性声明为
    retain
    时,您应该调用
    release
    以获取适当的变量。在你的
    [CCSprite spriteWithFile:@"SomeFile.png"];
    
    someSprite = [CCSprite spriteWithFile:@"SomeFile.png"];
    
    [self setsomeSprite] =[CCSprite spriteWithFile:@"SomeFile.png"];