我为NSArray创建了一个属性,用于创建一个getter / setter。我知道Apple建议在init和dealloc方法中使用实例变量。我试图在下面的代码中想要做什么。
(1)我是否需要额外的发布声明?对于dealloc,数组的保留计数是2还是1,留下泄漏。或者自动释放会照顾到这个吗?
(2)在xCode或工具中是否有某种方法可以跟踪特定变量以查看其在整个过程中的保留计数。
@property (nonatomic, retain) NSArray *array;
@synthesize arrary = _array;
- (id)initWithNibName:(NSString *)nibNameOrNil
bundle:(NSBundle *)nibBundleOrNil
initWithArray:(NSArray *)array
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
_array = [[NSArray alloc] initWithArray:array];
}
return self;
}
- (void)dealloc
{
[_array release];
[super dealloc];
}
答案 0 :(得分:2)
(1)我是否需要额外的发布声明?对于dealloc,数组的保留计数是2还是1,留下泄漏。或者自动释放会照顾到这个吗?
让我们一步一步:
@property (nonatomic, retain) NSArray *array;
// The setter in this case will do the proper ref counting:
@synthesize arrary = _array;
- (id)initWithNibName:(NSString *)nibNameOrNil
bundle:(NSBundle *)nibBundleOrNil
initWithArray:(NSArray *)array
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// _array is nil at allocation
_array = [[NSArray alloc] initWithArray:array]; // << self holds one reference
}
return self;
}
- (void)dealloc
{
[_array release]; // << self holds zero references
[super dealloc];
}
换句话说,你只需要。就个人而言,我只会在初始化程序和属性中使用copy
(而不是retain
)。
(2)在xCode或工具中是否有某种方法可以跟踪特定变量以查看其在整个过程中的保留计数。
是。但是,有几个运行时快捷方式和例外。
最简单的方法是使用分配仪器运行仪器,然后启用参考计数记录。然后它将记录每个单个对象的每个引用计数的回溯和时间。
答案 1 :(得分:0)
修改:已更改为符合Apple的建议。这个答案后面的评论是指我原来的(也是非常糟糕的)版本。将来,我将适当关注iOS Developer Library中的Practical Memory Management。
问题(1):不,您不需要额外的版本。在[[ASArray alloc] initWithArray:array]
之后,您的数组的保留计数将为1
。在dealloc
中,对[_array release]
的调用会将其返回0
,并且应该将其释放。
如果在此期间调用[setArray:]
,它将通过保留新对象和释放旧对象来遵守其retain
的属性声明。
如果某个其他对象或方法保留了您的阵列,则他们有责任释放它。如果您的数组的retainCount在1
开头时大于dealloc
,则其他一些对象会保留它,至少是暂时的。
问题(2):您可以在运行时检查retainCount
,但是当NSObject Protocol Reference发出警告时,您的对象很容易在多个自动释放池中结束,使其计数毫无意义。
奖励:您可能认为[[NSArray alloc] initWithArray:array]
将使用其输入的保留计数并添加1
。只有通过保留并传递对不可变源的引用来进行“复制”时才会发生这种情况,在这种情况下,某些其他对象也保留对该源的引用。 [[NSString alloc] initWithString:]
检测其源是否是不可变的并执行此操作; [[NSArray alloc] initWithArray:]
没有。另一方面,[NSArray copy]
将保留并自行返回。
这些优化当然是特定于实现的,不应该被假设。但是,构建一些对象,避免自动释放,并遵循他们的地址和retainCounts可能是有教育意义的,如下所示:
NSArray *array1 = [[NSArray alloc] initWithObjects:@"a", nil];
// Do not just assign array1 to [[NSArray alloc] init], or you'll get a singleton empty array with a high retain count.
// Make array1 mutable, and array2 should be copied differently.
NSLog(@"Constructed array1");
NSLog(@"array1 address = %p retainCount = %d", array1, [array1 retainCount]);
NSArray *array2 = [array1 copy];
// Use [[NSArray alloc] initWithArray:] and the results may be different.
NSLog(@"Constructed array2");
NSLog(@"array1 address = %p retainCount = %d", array1, [array1 retainCount]);
NSLog(@"array2 address = %p retainCount = %d", array2, [array2 retainCount]);
[array1 release];
NSLog(@"Released array1");
NSLog(@"array2 address = %p retainCount = %d", array2, [array2 retainCount]);
[array2 release];
答案 2 :(得分:0)
您的代码对我来说没问题。你不应该放一个额外的版本。在你的init方法中,_array的保留计数是1.在dealloc中释放之后,你应该做_array = nil,以避免悬空指针。
要检查泄漏,您可以执行以下任一或两项操作:
(i)CMD + Shift + B ---&gt;这会对您的代码进行分析,以发现这样的问题。
(ii)使用“仪器”中的“泄漏”和“分配”工具。在这里,您可以查看应用程序在执行时的分配和泄漏(如果有)。它非常有用,有时会捕获“分析”无法捕获的内容。