iPhone内存管理(附具体示例/问题)
大家好。我知道有人问过这个问题,但我仍然不清楚Objective-C中的内存管理。我觉得我已经很好地掌握了它,但我仍然希望以下代码有一些正确的答案。我有一系列的例子,我希望有人能澄清 设置实例变量的值: 假设我有一个iPhone内存管理(附具体示例/问题),iphone,objective-c,ios,memory-management,Iphone,Objective C,Ios,Memory Management,大家好。我知道有人问过这个问题,但我仍然不清楚Objective-C中的内存管理。我觉得我已经很好地掌握了它,但我仍然希望以下代码有一些正确的答案。我有一系列的例子,我希望有人能澄清 设置实例变量的值: 假设我有一个NSMutableArray变量。在我的类中,当我初始化它时,是否需要调用它上的retain 是吗 fooArray = [[[NSMutableArray alloc] init] retain]; 或 执行[[NSMutableArray alloc]init]是否已将reta
NSMutableArray
变量。在我的类中,当我初始化它时,是否需要调用它上的retain
是吗
fooArray = [[[NSMutableArray alloc] init] retain];
或
执行[[NSMutableArray alloc]init]
是否已将retain
计数设置为1,这样我就不需要对其调用retain
?另一方面,如果我调用了一个方法,我知道该方法返回一个autorelease
d对象,那么我肯定必须对它调用retain
,对吗?像这样:
fooString = [[NSString stringWithFormat:@"%d items", someInt] retain];
属性:
我询问retain
,因为我对@property
的自动setter的工作原理有点困惑
如果我将fooArray
设置为带有retain
集的@属性
,Objective-C将自动创建以下setter,对吗
- (void)setFooArray:(NSMutableArray *)anArray {
[fooArray release];
fooArray = [anArray retain];
}
所以,如果我有这样的代码:self.fooArray=[[NSMutableArray alloc]init]
(我认为这是有效的代码),Objective-C创建了一个setter方法,该方法对分配给fooArray
的值调用retain
。在这种情况下,retain
计数实际上是2吗
设置属性值的正确方法:
我知道在这方面和(可能)辩论中存在一些问题,但设置@属性的正确方法是什么
这个
还是这个
NSMutableArray *anArray = [[NSMutableArray alloc] init];
self.fooArray = anArray;
[anArray release];
我想澄清一下这些例子。谢谢 首先,这一行:
fooArray = [[NSMutableArray alloc] init];
fooArray的保留计数将自动为1
第二,是的,是2。您对setter实现的猜测是正确的
第三,后者是正确的根据苹果的说法,任何以alloc
或new
开头的方法,或包含copy
的方法,都属于调用方
要获得对象的所有权,您必须保留它
因此,在第一个示例中,retain
是不必要的,因为您已经拥有该对象
正确的方法是:
fooArray = [[NSMutableArray alloc] init];
由于autorelease
对象属于当前自动释放池,因此必须对其调用retain
,以获得它们的所有权,因此此示例是正确的:
fooString = [[NSString stringWithFormat:@"%d items", someInt] retain];
这也很好:
self.fooString = [NSString stringWithFormat:@"%d items", someInt]; //retained by property setter
对于最后一个使用属性设置器的示例,这是正确的方法:
NSMutableArray *anArray = [[NSMutableArray alloc] init];
self.fooArray = anArray;
[anArray release];
我建议采用以下解决方案,而不必执行上述操作:
self.fooArray = [NSMutableArray arrayWithCapacity:10];
arrayWithCapacity:
将返回一个自动删除的NSMutableArray
,这是由属性设置器方法设置的保留
。) 理想情况下,您希望尽可能使用访问器,尤其是在处理对象时,因为它们有助于避免许多内存问题。因此,即使是实例变量,您也应该:
self.fooArray = ...;
而不是
fooArray = ...;
您应该为对象实例变量声明属性的原因是,内存管理稍微复杂一些,每次手动重新创建它都很棘手。非原子保留属性的正确setter如下所示:
- (void)setFoo:(NSArray *)aFoo {
if (foo == aFoo) {
return;
}
NSArray *oldFoo = foo;
foo = [aFoo retain];
[oldFoo release];
}
在执行类似操作时(假设保留了foo),实例变量的retain计数为2是正确的:
第一个保留计数来自alloc
,第二个来自合成setter。其中任何一项都应该有效:
// longer, explicit version, releases immediately (more efficient)
NSMutableArray *aFoo = [[NSMutableArray alloc] init];
self.foo = aFoo;
[aFoo release];
// autoreleased, not so bad unless you're a memory management freak
self.foo = [[[NSMutableArray alloc] init] autorelease];
// an even shorter version of the above
self.foo = [NSMutableArray array];
要创建私有属性,可以在.m实现文件中将它们声明为类扩展名。举个例子,考虑一个简单的对象对象,它有一个名称,和一个布尔属性<代码> Debug Save>代码>,它简单地指示对象是否被保存到某个数据库中。由于我们不想将其公开给外界,但仍将属性的好处保留在实现文件中,因此我们可以创建头文件,该文件将包含所有实例变量(public、private、protected),并且仅包含公共属性:
// Person.h
@interface Person {
NSString *name;
@private
BOOL didSave;
}
@property (nonatomic, retain) NSString *name;
@end
但是在实现内部声明私有属性:
// Person.m
// property is declared as a class extension, making it
// invisible to the outside world.
@interface Person ()
@property BOOL didSave;
@end
@implementation
// synthesize as normal
@synthesize name, didSave;
@end
我知道创建临时数组的对象来分配属性数组很好,但是self.fooArray=[[NSMutableArray alloc]init]有什么问题;为什么它会出现内存泄漏。@Ishu Gupta,这里有一个内存泄漏,因为您已经拥有了该对象,因为您在该行调用了alloc
,并且您的@属性setter可能有retain
修饰符,所以该赋值的最终结果变成self.fooArray=[[NSMutableArray alloc]init]retain]
,因此泄漏。@Ishu Gupta我很高兴能帮上忙:)这真是一个很好的解释。谢谢你,雅各布。我的一些疑问现在已经清楚了。谢谢你的回答,阿努拉格。当我不需要其他类可以访问变量时,我一直试图避免使用属性。有点像n00b问题,但是。。。我可以拥有其他类无法访问的属性吗?谢谢你的编辑,Anurag。如果你不介意的话,我想问几个问题。。能否在.m的@interface中声明canSave变量?在我看来,未公开的变量已经是隐式私有的,因此必须将其标记为私有似乎有点多余。我听到您提到了私有实例变量部分,但不幸的是,这是我们可以通过Objective-C将实现细节保持私有的最接近方法。如果我们不将变量标记为私有,然后默认情况下,它们具有受保护的访问权限,这可能是需要的,也可能不是需要的。
// longer, explicit version, releases immediately (more efficient)
NSMutableArray *aFoo = [[NSMutableArray alloc] init];
self.foo = aFoo;
[aFoo release];
// autoreleased, not so bad unless you're a memory management freak
self.foo = [[[NSMutableArray alloc] init] autorelease];
// an even shorter version of the above
self.foo = [NSMutableArray array];
// Person.h
@interface Person {
NSString *name;
@private
BOOL didSave;
}
@property (nonatomic, retain) NSString *name;
@end
// Person.m
// property is declared as a class extension, making it
// invisible to the outside world.
@interface Person ()
@property BOOL didSave;
@end
@implementation
// synthesize as normal
@synthesize name, didSave;
@end