【问题标题】:iPhone init method issueiPhone初始化方法问题
【发布时间】:2012-04-12 01:42:27
【问题描述】:

我为创建 getter/setter 的 NSArray 创建了一个属性。我知道 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];
}

【问题讨论】:

  • results 中的 [[NSArray alloc] initWithArray:results]; 是什么?
  • 对不起,应该是数组。只是从另一个类传递的数组

标签: iphone objective-c ios


【解决方案1】:

(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 或工具中是否有某种方法可以跟踪特定变量以查看其保留计数在整个过程中的过程。

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

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

【讨论】:

  • 谢谢,你提到了copy,当你通过init传递变量时,你会如何使用它?
  • @Vikings 具有声明为 @property (nonatomic, copy) NSArray *array; 的属性和初始化器 _array = [array copy];(尽管 _array = [[NSArray alloc] initWithArray:array]; 完成相同的事情)。
【解决方案2】:
  1. 您的代码在我看来没问题。您不必添加额外的版本。在您的 init 方法中,_array 的保留计数为 1。在 dealloc 中释放后,您应该执行 _array = nil,以避免悬空指针。

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

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

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

【讨论】:

  • 不需要设置_array = nil
【解决方案3】:

编辑:更改为符合 Apple 的建议。遵循此答案的 cmets 指的是我的原始(并且非常糟糕)版本。以后会适当关注iOS开发者库中的Practical Memory Management

问题 (1):不,您不需要额外的版本。在[[ASArray alloc] initWithArray:array] 之后,您的数组将具有1 的保留计数。在dealloc 中,对[_array release] 的调用将把它返回给0,它应该被释放。

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

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

问题 (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];

【讨论】:

  • 但是要小心...这段代码会导致过度保留 -> self.array = [[NSArray alloc] initWithArray:array]
  • @borrrden 如果我在分配后自动释放,那应该妥善处理,或者有更优雅的方式
  • @Vikings 是的,如果您使用属性分配它,那就是这样做的方法。或者你可以做你所做的并分配给实例变量。如果 Apple 建议您这样做,那么您无论如何都应该强烈考虑遵循该建议:)。
  • @Vikings:如果你需要分配一些东西,是的,你会使用self.array = [[[NSArray alloc] initWithArray:array] autorelease]。但是,NSArray 提供了[NSArray arrayWithArray:] 类方法来实现相同的目标。我已经编辑了我的答案以使用它复制您的输入数组。
  • @Dondragmer Apple 的文档警告不要在 dealloc 中使用 setter。相反,他们说你应该释放实例变量,在这种情况下是 _array
猜你喜欢
  • 2022-01-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-21
  • 2020-12-25
  • 2011-10-13
  • 2011-10-29
  • 2020-10-17
相关资源
最近更新 更多