【问题标题】:Why shouldn't I use Objective C 2.0 accessors in init/dealloc? [closed]为什么我不应该在 init/dealloc 中使用 Objective C 2.0 访问器? [关闭]
【发布时间】:2010-09-16 14:28:05
【问题描述】:

@mmalc'sresponsethis question 中,他声明“一般情况下,您应该在 dealloc(或 init)中使用访问器方法。”为什么mmalc会这样说?

我能想到的唯一真正原因是性能和避免@dynamic setter 的未知副作用。

讨论?

【问题讨论】:

  • OP 没有以“讨论”结束?这不会被关闭。这是一个非常合理和有用的问题——非常具有建设性。

标签: objective-c cocoa


【解决方案1】:

它基本上是一个将错误可能性降至最低的指南。

在这种情况下,您的 setter/getter 可能会不经意间对对象的状态做出直接或间接的假设。当对象处于设置或销毁过程中时,这些假设可能会成为问题。

例如,在下面的代码中,观察者不知道“示例”正在被销毁,并且可以假设其他已被释放的属性是有效的。

(您可以争辩说您的对象应该在自行拆除之前移除所有观察者,这是一种很好的做法,也是防止意外问题的另一个准则)。

@implementation Example

-(void) setFoo:(Foo*)foo
{
   _foo = foo;
  [_observer onPropertyChange:self object:foo];
}

-(void) dealloc
{
   ...
   self.foo = nil;
}

@end

【讨论】:

【解决方案2】:

这就是使用惯用一致的代码。如果您正确地对所有代码进行模式化,则有一组规则可以保证在 init/dealloc 中使用访问器是安全的。

最大的问题是(正如 mmalc 所说)设置属性默认状态的代码不应通过访问器,因为它会导致各种令人讨厌的问题。问题是 init 没有理由设置属性的默认状态。出于多种原因,我一直在使用自初始化的访问器,如下面的简单示例:

- (NSMutableDictionary *) myMutableDict {
    if (!myMutableDict) {
        myMutableDict = [[NSMutableDictionary alloc] init];
    }

    return myMutableDict;
}

这种类型的属性初始化允许延迟许多实际上可能不需要的初始化代码。在上述情况下,init 不负责初始化属性状态,在 init 方法中使用访问器是完全安全的(甚至是必要的)。

诚然,这确实对您的代码施加了额外的限制,例如,对超类中的属性具有自定义访问器的子类必须调用超类访问器,但这些限制与 Cocoa 中常见的各种其他限制并没有冲突。

【讨论】:

  • 有趣的一点,但请注意(除非您假设垃圾收集?)您给出的示例离开 myMutableDict 自动释放...
  • 此外,您不能将nil 分配给此属性,因为访问器会自动创建一个数组的新实例。
  • 这是将施加的附加限制之一,它不会使这一点无效。在许多情况下,您永远不会在拆卸期间将 nil 分配给特定属性 accept (在这种情况下,这仍然可以正常工作)。我最好的例子就是 redonly 的属性。
  • 另外,当我在这里时,不妨对其进行编辑以确保保留/释放的安全。
  • IMO,这段代码对于只读属性来说只是花花公子,而不是对于读写对。一般来说,我相信object.x = foo 应该暗示紧接着object.x == fooYES。如果没有,也许(非属性)方法会更好。
【解决方案3】:

您回答了自己的问题:

  1. 性能本身可能是一个完全充分的理由(特别是如果您的访问器是原子的)。
  2. 您应该避免访问器可能产生的任何副作用。

如果您的类可能是子类,则后者尤其是一个问题。

不过,不清楚为什么在 Objective-C 2 访问器中专门解决了这个问题?无论您是使用声明的属性还是自己编写访问器,都适用相同的原则。

【讨论】:

    【解决方案4】:

    可能是 setter 具有应该运行的逻辑,或者可能是实现使用了一个名称与 getter/setter 不同的 ivar,或者可能是两个需要释放和/或将其值设置为 nil 的 ivar。唯一可靠的方法是调用 setter。 setter 有责任编写成在 init 或 dealloc 期间调用时不会发生不良副作用的方式。

    来自“Cocoa 设计模式”,Buck,Yacktman,第 115 页:“...当您在现代 Objective-C 运行时或...中使用合成实例变量时,除了使用访问器之外,没有其他实用的替代方法...”

    【讨论】:

    • 在我的问题 (stackoverflow.com/questions/1283419) 中,其中一个答案显示即使您只是声明属性(合成的 ivar),您仍然可以直接访问 ivar。
    • @Dave 直接访问 ivar 假定您知道它的名称,并且 setter 只更改了一个 ivar。但是不应该知道(或关心)setter 是如何实现的。
    • Setters/Getters 可以被覆盖。他们可以释放其他资源(例如观察者)。
    【解决方案5】:

    事实上,对于一个频繁出现和消失的类(如细节视图控制器),您希望在 init 中使用访问器;否则,您最终可能会在 viewDidUnload 中释放一个您稍后尝试访问的值(它们在 CS193P 中显示...)

    【讨论】:

      【解决方案6】:

      您可以通过在分配/解除分配时不调用设置器来创建相同的问题。

      我不认为直接在 init/dealloc 中使用 retain/release 可以实现任何目标。您只需更改可能的错误集。

      每次您必须考虑财产分配/解除分配的顺序。

      【讨论】:

        猜你喜欢
        • 2011-03-26
        • 2013-04-03
        • 1970-01-01
        • 2013-06-20
        • 1970-01-01
        • 2010-11-19
        • 1970-01-01
        • 2011-11-07
        • 2010-09-13
        相关资源
        最近更新 更多