24

我现在从几个来源(stackoverflow.com、cocoa-dev、文档、博客等)听说在 init 和 dealloc 方法中使用访问器和设置(foo、setFoo:) 是“错误的”。我了解,如果您这样做,则极有可能混淆正在观察该属性的其他对象。(这里给出一个简单的例子)

但是,我不得不说,我不同意这种做法,原因如下:

新的 Objective-C 运行时(iPhone 上的运行时和 10.5 中的 64 位运行时)允许您声明属性而无需声明相应的 ivar。例如,以下类将在 10.5 或 iPhone(设备,而不是模拟器)上编译得很好:

@interface Foo : NSObject { }

  @property (retain) id someObject;

@end

@implementation Foo

  @synthesize someObject;

@end

了解以上是一个完全有效的 Objective-C 类,假设我决定编写一个初始化程序,并且出于内存管理的目的,一个 dealloc 方法(因为 GC 在 iPhone 上不可用)。我读过的关于初始化器和释放的所有内容都会引导我编写以下两种方法:

- (id) init {
  if (self = [super init]) {
    //initialize the value of someObject to nil
    [self setSomeObject:nil];
  }
  return self;
}

- (void) dealloc {
  //setting someObject to nil will release the previous value
  [self setSomeObject:nil];
  [super dealloc];
}

但是,根据文档和流行观点,这是“错误的”。所以我的问题是这样的:

  1. 我应该如何在不使用访问器的情况下初始化 someObject ?您可能会说编译器(或运行时或其他)将确保 someObject 已设置为 nil,但我认为依赖它是不恰当的行为。拥有良好的 C 语言背景,由于没有正确初始化变量,我已经看到了相当多的错误,这似乎没什么不同。
  2. 如果我不应该在 dealloc 方法中使用访问器,我该如何释放 someObject?

如果其中任何一个的答案是“你不能”,那么在你的 init 和 dealloc 方法中使用访问器有什么不好呢?

4

2 回答 2

9

编辑(2013 年 2 月 13 日):正如我在下面的评论中所指出的,尤其是自从添加了 ARC 之后,我改变了主意。在 ARC 之前,我看到了很多由于init. IMO,尤其是与初级团队合作,使用访问器的罕见问题init被 ivar 访问的常见错误所抵消。由于 ARC 已经消除了这些类型的 bug,因此使用访问器 ininit可能导致的罕见但可能的 bug 更为重要,因此我已转而支持在 and 中直接使用 ivars initdealloc并且仅在那些地方;其他任何可能的访问器(显然你不能在访问器本身内部使用访问器......)


弧前答案

我强烈不同意那些反对-init. 在几乎所有情况下,这是一个使用访问器的好地方,并且它节省了我在新 Cocoa 编码器中看到的许多错误,这些错误在分配-init.

-dealloc是一个更艰难的决定。我很自然地倾向于在那里使用访问器(以便在任何地方使用它们),但是由于 KVO(如果您在设置器中发布更改通知,甚至是 NSNotifications)可能会导致头痛。也就是说,虽然我没有在 中使用访问器-dealloc,但我认为它非常值得商榷,Apple 对此非常不一致(例如,我们知道他们正在调用setView:UIViewController -dealloc)。

无论如何,我会说访问器使用不足导致的错误是过度使用的 100 倍。除非有充分的理由不使用它们,否则我总是会错误地使用它们。

于 2009-08-17T05:03:04.500 回答
8

我了解当前无法直接访问合成 ivars 的 10.5 行为被 Apple 认为是一个错误;您应该能够直接访问它,但不能。

因此,您应该能够:

someObject = nil;

代替

self.someObject = nil;

同时,直接使用访问器是不提供显式 ivar 的唯一方法。

更新:此错误已修复;你现在可以做得someObject = nil很好。

于 2009-08-16T04:13:31.740 回答