0

我为 NSArray 创建了一个属性,它创建了一个 getter/setter。我知道 Apple 建议在 init 和 dealloc 方法中使用实例变量。我试图弄清楚在下面的代码中要做什么。

(1) 我需要额外的发布声明吗?数组的保留计数不会是 2,然后是 1 与 dealloc,留下泄漏。或者 autorelease 会解决这个问题吗?

(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];
}
4

3 回答 3

2

(1) 我需要额外的发布声明吗?数组的保留计数不会是 2,然后是 1 与 dealloc,留下泄漏。或者 autorelease 会解决这个问题吗?

让我们一步一步来:

@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 或仪器中是否有某种方法可以跟踪特定变量以查看其保留计数通过该过程。

是的。但是,有几个运行时快捷方式和例外情况。

最简单的方法是使用分配工具运行工具,然后启用引用计数记录。然后它将记录每个单独对象的每个引用计数的回溯和时间。

于 2012-04-13T05:12:21.147 回答
0

编辑:更改为符合 Apple 的建议。此答案后面的评论指的是我的原始(并且非常糟糕)版本。以后,我会适当关注iOS 开发者库中的实用内存管理

问题 (1):不,您不需要额外的版本。之后[[ASArray alloc] initWithArray:array],您的数组将有一个保留计数1。在dealloc中,对 的调用[_array release]会将其返回到0,并且应该将其释放。

如果[setArray:]同时被调用,它将遵守其属性声明,retain保留新对象释放旧对象。

如果其他对象或方法保留了您的数组,则他们有责任释放它。如果您的数组的 retainCount 大于1的开头dealloc,则其他一些对象正在保留它,至少是暂时的。

问题 (2):您可以retainCount在运行时检查,但正如NSObject 协议参考所警告的那样,您的对象很容易在多个自动释放池中结束,从而使其计数高得毫无意义。

奖励:您可能会认为[[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];
于 2012-04-12T01:50:46.753 回答
0
  1. 你的代码对我来说看起来不错。你不应该放一个额外的版本。在您的 init 方法中,_array 的保留计数为 1。在 dealloc 中释放后,您应该执行 _array = nil,以避免悬空指针。

  2. 要检查泄漏,您可以执行以下一项或两项操作:

(i) CMD + Shift + B ---> 这将对您的代码运行分析以发现此类问题。

(ii) 使用“工具”中的“泄漏”和“分配”工具。在这里,您可以查看应用程序在执行时的分配和泄漏(如果有)。它非常有用,有时可以捕捉到“分析”没有捕捉到的东西。

于 2012-04-12T03:37:07.050 回答