iPhone的内存pipe理(具体的例子/问题)
大家好。 我知道这个问题已经被问到了,但是Objective-C中的内存pipe理我还没有清晰的描述。 我觉得我有一个很好的把握,但我仍然喜欢以下代码的一些正确的答案。 我有一系列的例子,我希望有人澄清。
为实例variables设置一个值 :
说我有一个NSMutableArray
variables。 在我的课上,当我初始化它,我需要调用一个retain
吗?
我可以吗?
fooArray = [[[NSMutableArray alloc] init] retain];
要么
fooArray = [[NSMutableArray alloc] init];
是否[[NSMutableArray alloc] init]
已经将retain
计数设置为1,所以我不需要调用retain
? 另一方面,如果我调用一个我知道的方法返回一个autorelease
对象,我肯定会调用retain
,对吧? 像这样:
fooString = [[NSString stringWithFormat:@"%d items", someInt] retain];
属性 :
我问retain
因为我有点困惑如何@property
的自动设置工程。
如果我将fooArray
设置为带有retain
集的@property
fooArray
,Objective-C将自动创build下面的setter,对吗?
- (void)setFooArray:(NSMutableArray *)anArray { [fooArray release]; fooArray = [anArray retain]; }
所以,如果我有这样的代码: self.fooArray = [[NSMutableArray alloc] init];
(我相信是有效的代码),Objective-C创build一个setter方法,调用retain
在分配给fooArray
的值上。 在这种情况下, retain
计数实际上是2吗?
正确设置属性值的方法 :
我知道有这个问题和(可能)辩论,但这是正确的方式来设置@property
?
这个?
self.fooArray = [[NSMutableArray alloc] init];
或这个?
NSMutableArray *anArray = [[NSMutableArray alloc] init]; self.fooArray = anArray; [anArray release];
我希望对这些例子进行一些澄清。 谢谢!
理想情况下,只要有可能,就要使用访问器,尤其是在处理对象时,可以避免许多内存问题。 所以即使对于实例variables,你也应该这样做:
self.fooArray = ...;
代替
fooArray = ...;
你应该为对象实例variables声明属性的原因是因为内存pipe理稍微复杂一些,每次手动重新创build都是棘手的。 非primefaces保留属性的正确设置方法如下所示:
- (void)setFoo:(NSArray *)aFoo { if (foo == aFoo) { return; } NSArray *oldFoo = foo; foo = [aFoo retain]; [oldFoo release]; }
当你做这样的事情(假设foo被保留)的时候,你对保留数为2的实例variables是正确的:
self.foo = [[NSMutableArray alloc] init];
第一个保留计数来自alloc
,第二个来自合成二叉树。 任何这些应该工作:
// 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];
要创build私有属性,可以在.m实现文件中声明它们作为类扩展。 举一个例子,考虑一个简单的Person对象,它有一个名字和一个布尔属性didSave
,它只是表示对象是否被保存到某个数据库。 既然我们不想把这个暴露给外部世界,但是在实现文件中仍然保留属性的好处,我们可以创build头文件将所有的实例variables(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
根据苹果的对象所有权政策 ,任何以“ alloc
或“ new
,或者包含copy
都是由调用者拥有的。
要获得对象的所有权,您必须retain
它。
所以,在你的第一个例子中, retain
是不必要的,因为你已经拥有这个对象。
正确的方法来做到这一点:
fooArray = [[NSMutableArray alloc] init];
由于autoreleased
对象属于当前的自动释放池,所以你必须调用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];
而不是必须做到上述,我会build议以下解决scheme:
self.fooArray = [NSMutableArray arrayWithCapacity:10];
arrayWithCapacity:
将返回一个自动释放的NSMutableArray
,这是属性setter方法的retain
。 🙂
首先,用这一行:
fooArray = [[NSMutableArray alloc] init];
fooArray将自动具有1的保留计数。
其次,是的,它是2.你猜测的实现是正确的。
第三,后者是对的