Iphone 内存管理-如何最好地初始化标头中声明的实例

Iphone 内存管理-如何最好地初始化标头中声明的实例,iphone,objective-c,memory-management,release-management,Iphone,Objective C,Memory Management,Release Management,我读过一些关于这方面的帖子,但有一件事我还不清楚。我知道这可能是一个n00b问题,但我实际上已经深入到开发中,没有完全掌握这个基本问题。我想这是自学成才的症状 在标头中声明一个变量,如下所示: @interface SomeClass : NSObject { NSMutableArray *anArray; } @property (nonatomic, retain) NSMutableArray *anArray; end 然后在主文件中对其进行合成,并将其设置为初始值:

我读过一些关于这方面的帖子,但有一件事我还不清楚。我知道这可能是一个n00b问题,但我实际上已经深入到开发中,没有完全掌握这个基本问题。我想这是自学成才的症状

在标头中声明一个变量,如下所示:

@interface SomeClass : NSObject {
    NSMutableArray *anArray;
}

@property (nonatomic, retain) NSMutableArray *anArray;

end
然后在主文件中对其进行合成,并将其设置为初始值:

    @implementation SomeClass

@synthesize anArray

- (SomeClass *)init{
    if (self = [super init]) {
        self.anArray = [[NSMutableArray alloc] initWithCapacity:10];
}
[return self];
并在您的类解除锁定时释放它:

- (void)dealloc {
[anArray release];
[super dealloc];
}
现在,当我运行仪器时,线路

self.anArray = [[NSMutableArray alloc] initWithCapacity:10];
被识别为内存泄漏。这是否是内存泄漏,因为在标头中定义变量anArray时,它会分配内存?因为我认为它是一个空指针。因此,当您要初始化它并调用[[NSMutableArray alloc]initWithCapacity:10]时,您正在重新分配内存,并且丢失指向原始分配的指针

因此,我使用便利类方法:

@implementation SomeClass

    @synthesize anArray

    - (SomeClass *)init{
        if (self = [super init]) {
            self.anArray = [NSMutableArray arrayWithCapacity:10];
    }
    [return self];
这不再被认为是仪器中的内存泄漏。由于这是一种方便的方法,anArray是自动释放的。但是,如果我假设头中的实例声明分配内存(这可以解释前面的问题),那么我是否仍然应该释放anArray?以这种方式设置初始值是否会保留它

我理解两者之间的区别

NSMutableArray *anArray = [[NSMutableArray alloc] initWithCapacity:10];

但我不确定我是否理解的是,当您在头文件中声明NSMutableArray*anArray时,应该使用哪种方法以及为什么。无论是否使用第二种方法,在调用dealloc时仍应释放anArray

我可能会补充说,我发现以下帖子/链接很有用:


分配内存的不是实例。您可以正确地假设,在Objective-C中,至少在所有基于Apple的操作系统上,新初始化的类的所有IVAR都设置为0、nil或NULL(视情况而定)

您看到的问题是在初始化中使用的是属性,而不是ivar。由于您已将属性声明为retain,因此使用属性访问器将其设置为自动将其保留

因此,当您初始化时,您要么直接获得所有权并设置ivar,要么像您现在做的那样,使用属性访问器设置属性,然后通过释放您拥有的对象放弃init方法中的所有权,或者像在第二个实例中一样,使用便利构造函数,这样您就不会拥有返回的实例

所以请记住,如果您使用了属性访问器,即使在类本身中,您也会获得在属性上设置的特性,例如,非原子、保留等。。无论何时执行以下操作之一,都可以使用属性访问器:

// in these cases the property takes ownership through the
// retain keyword, so you must not take ownership yourself
self.anArray = something;
[self setAnArray:something];
[self setValue:something forKey:@"anArray"];
您可以直接访问ivar,如:

anArray = something; // in this case you must take ownership

分配内存的不是实例。您可以正确地假设,在Objective-C中,至少在所有基于Apple的操作系统上,新初始化的类的所有IVAR都设置为0、nil或NULL(视情况而定)

您看到的问题是在初始化中使用的是属性,而不是ivar。由于您已将属性声明为retain,因此使用属性访问器将其设置为自动将其保留

因此,当您初始化时,您要么直接获得所有权并设置ivar,要么像您现在做的那样,使用属性访问器设置属性,然后通过释放您拥有的对象放弃init方法中的所有权,或者像在第二个实例中一样,使用便利构造函数,这样您就不会拥有返回的实例

所以请记住,如果您使用了属性访问器,即使在类本身中,您也会获得在属性上设置的特性,例如,非原子、保留等。。无论何时执行以下操作之一,都可以使用属性访问器:

// in these cases the property takes ownership through the
// retain keyword, so you must not take ownership yourself
self.anArray = something;
[self setAnArray:something];
[self setValue:something forKey:@"anArray"];
您可以直接访问ivar,如:

anArray = something; // in this case you must take ownership

分配对象时,引用计数为1。 设置具有“retain”属性的属性也会增加引用计数

所以,这意味着这通常是不好的:

@property (nonatomic, retain) Object * variable;

因为变量现在的引用计数为2

设置对象的成员变量时,只需执行以下操作:

variable = [[Object alloc] init];
你也应该意识到这是有效的

        self.anArray = [NSMutableArray arrayWithCapacity:10];

因为arrayWithCapacity和其他类似的factor方法会自动删除它返回的对象,所以在设置属性后,它的引用计数基本上为1。

分配对象时,引用计数为1。 设置具有“retain”属性的属性也会增加引用计数

所以,这意味着这通常是不好的:

@property (nonatomic, retain) Object * variable;

因为变量现在的引用计数为2

设置对象的成员变量时,只需执行以下操作:

variable = [[Object alloc] init];
你也应该意识到这是有效的

        self.anArray = [NSMutableArray arrayWithCapacity:10];
因为arrayWithCapacity和其他类似的因子方法会自动释放o
对象返回,因此在设置属性后,它的引用计数基本上为1。

感谢您如此清楚地说明这一点。因此,如果我执行self.anArray=[nsmutableArrayWithCapacity:10];我仍然需要在解除锁定时释放anArray,因为它的引用计数仍然为1。每次我调用self.anArray=somethine时,引用计数都会增加1吗?在这种情况下,不使用self直接设置ivar会更安全?是的,您仍然需要释放它。并不是每次调用“self.anArray=something”时,数字都会增加,因为引用计数与对象相关,而不是与变量相关。通常,“self.anArray=something”将释放旧对象并保留新对象。使用“self.varname=something”通常是一种良好的做法,因为这样您将始终释放旧对象。正如我所展示的,异常在init方法中,您刚刚分配了对象,并且变量中肯定没有存储以前的对象。感谢您如此清楚地说明这一点。因此,如果我执行self.anArray=[nsmutableArrayWithCapacity:10];我仍然需要在解除锁定时释放anArray,因为它的引用计数仍然为1。每次我调用self.anArray=somethine时,引用计数都会增加1吗?在这种情况下,不使用self直接设置ivar会更安全?是的,您仍然需要释放它。并不是每次调用“self.anArray=something”时,数字都会增加,因为引用计数与对象相关,而不是与变量相关。通常,“self.anArray=something”将释放旧对象并保留新对象。使用“self.varname=something”通常是一种良好的做法,因为这样您将始终释放旧对象。正如我所展示的,异常在init方法中,您刚刚分配了对象,并且变量中肯定没有存储以前的对象。感谢详细的回答-它真的很有帮助。当您说使用属性访问器设置属性,然后通过释放您拥有的对象放弃init方法中的所有权时,有一点我不明白。。。因此,如果我在init方法中调用self.anArray=[[NSMutableArray alloc]init],我也需要在init方法中释放它?还有当我解除锁定时?这就是为什么人们有时会做NSArray*anArray=[[NSArray alloc]init];self.classArray=anArray;[阵列释放]@是的,这正是他们这么做的原因。因此,如果您执行原始操作,即self.anArray=[[NSMutableArray alloc]init],基本上保证会泄漏它。基本上,由于该属性被声明为保留,因此它拥有所有权,因此您需要放弃所有权,即释放它。因此,我的选项是:anArray=[[NSArray alloc]init]必须仅在dealloc中调用[anArray release]| self.anArray=[NSArray array]不需要释放任何东西| |如果我做了self.anArray=[[NSArray alloc]init]然后必须在init方法和dealloc方法BAD| |中调用[anArray release],最后是我在评论中提到的方法。在anArray=[[NSArray alloc]init]和self.anArray=tempArray中,哪个更好,其中tempArray的分配和发布如上所述。非常感谢,顺便说一句!任何时候,当您有一个copy或retain属性时,您必须在dealloc中释放它,这样它就不会改变。你仍然要负责清理。唯一的区别是你/分配/它的方式。在类内部,您可以直接将其分配给ivar,在这种情况下,您必须保留和维护所有权,即创建而不是发布或保留它。如果你通过属性访问器分配它,你必须释放所有权,例如,如果你创建了它,你必须释放它。。。我想我明白了。因此,最好不要使用self.ivar在类的init方法中赋值,因为这样就需要释放ivar。但是,如果您直接将值分配给ivar,那么释放和保留取决于您如何分配它-无论是使用类方法autoreleases还是使用实例方法,您都必须释放它。是这样吗?谢谢你的耐心。顺便说一句:谢谢你的详细回答,这真的很有帮助。当您说使用属性访问器设置属性,然后通过释放您拥有的对象放弃init方法中的所有权时,有一点我不明白。。。因此,如果我在init方法中调用self.anArray=[[NSMutableArray alloc]init],我也需要在init方法中释放它?还有当我解除锁定时?这就是为什么人们有时会做NSArray*anArray=[[NSArray alloc]init];self.classArray=anArray;[阵列释放]@是的,这正是他们这么做的原因。因此,如果您执行原始操作,即self.anArray=[[NSMutableArray alloc]init],基本上保证会泄漏它。基本上,由于属性被声明为retain,它拥有所有权,因此您需要放弃所有权,即释放它。因此,我的选项是:anArray=[[NSArray alloc]init]必须仅在dealloc中调用[anArray release]| self.anArray=[NSArray array]无需释放
e anything | | |如果我确实执行self.anArray=[[NSArray alloc]init],那么必须在init方法以及dealloc方法中调用[anArray release]BAD | | |最后,我在评论中提到的方法。在anArray=[[NSArray alloc]init]和self.anArray=tempArray中,哪个更好,其中tempArray的分配和发布如上所述。非常感谢,顺便说一句!任何时候,当您有一个copy或retain属性时,您必须在dealloc中释放它,这样它就不会改变。你仍然要负责清理。唯一的区别是你/分配/它的方式。在类内部,您可以直接将其分配给ivar,在这种情况下,您必须保留和维护所有权,即创建而不是发布或保留它。如果你通过属性访问器分配它,你必须释放所有权,例如,如果你创建了它,你必须释放它。。。我想我明白了。因此,最好不要使用self.ivar在类的init方法中赋值,因为这样就需要释放ivar。但是,如果您直接将值分配给ivar,那么释放和保留取决于您如何分配它-无论是使用类方法autoreleases还是使用实例方法,您都必须释放它。是这样吗?谢谢你的耐心,顺便说一句:s