【问题标题】:Why shoudn't I use accessor methods in init methods为什么我不应该在 init 方法中使用访问器方法
【发布时间】:2011-03-26 08:39:16
【问题描述】:

来自 Apple 关于Memory Management 的文档:

您不应该使用访问器方法来设置实例变量的唯一地方是 init 方法和 dealloc。要使用表示零的数字对象来初始化计数器对象,您可以实现一个 init 方法,如下所示:

要允许使用非零计数来初始化计数器,您可以实现一个 initWithCount: 方法,如下所示:

- initWithCount:(NSNumber *)startingCount {
    self = [super init];
    if (self) {
        count = [startingCount copy];
    }
    return self;
}

为什么不呢?

【问题讨论】:

  • 您可以添加指向您的文档来源的链接吗?
  • [为什么我不应该在 init/dealloc 中使用 Obective C 2.0 访问器? ](stackoverflow.com/questions/192721/…)
  • @Scott:我刚刚在问题本身中添加了一个链接。
  • 即使我找不到一个清晰简单的答案,我猜 Perspx 是对的,这与这个question 是重复的。

标签: objective-c memory-management


【解决方案1】:

在现代目标 C 中,您应该能够在 init 中使用访问器方法。如果几乎永远不会发生编译器错误,则很少发生

【讨论】:

    【解决方案2】:

    JeremyP 提出了一个很好的观点。由于 setter 调用的语法总是涉及“self”,其类型在运行时确定,因此如果“self”确实是子类对象,则子类实例可以调用其覆盖版本的 setter...

    但是,在某些情况下,您必须在初始化程序中使用 setter。这是在超类中声明实例变量的时候;无论如何你都不能直接访问实例变量,所以你必须使用 setter。

    另一种情况是属性使用延迟初始化。在这种情况下,您必须通过 getter;如果你不这样做,实例变量将永远没有机会被初始化。例如,EOCPerson 类可能有一个属性可以访问代表每个人大脑的复杂对象。如果这个属性不经常被访问并且设置起来很昂贵,你可以在 getter 中懒惰地初始化它,像这样:

    - (EOCBrain*)brain { if (!_brain) {
            _brain = [Brain new];
        }
    return _brain; }
    

    如果您要直接访问实例变量并且尚未调用getter,则不会设置brain,并且您必须调用访问器来访问brain 属性。

    -- Matt Galloway 的 EOC 书籍 Item7

    【讨论】:

      【解决方案3】:

      查看我对this question的回复。

      主要原因是因为子类可能会覆盖您的访问器并做一些不同的事情。子类的访问器可能假定一个完全初始化的对象,即子类的 init 方法中的所有代码都已运行。事实上,当您的 init 方法运行时,它们都没有。类似地,子类的访问器可能依赖于子类的 dealloc 方法没有运行。当您的 dealloc 方法正在运行时,这显然是错误的。

      扩展你的例子,如果你已经完成了

      - initWithCount:(NSNumber *)startingCount {
          self = [super init];
          if (self) {
              [self setCount: [startingCount copy]];
          }
          return self;
      }
      

      但是一个子类覆盖了 setCount: 做一些除了设置你的计数变量之外的事情,你可能会遇到麻烦。

      【讨论】:

        【解决方案4】:

        仅从 OOP 的角度来看(因为我没有使用 Objective-c 的经验),您不会使用当前正在构建的对象的方法。这在某些语言中是可能的,但您已经可以访问私有变量。对象构造尚未完成,因此尚未准备好对其进行操作。一旦对象被构造出来,它就处于一个已知的良好状态(或者假设是这样)并且它可以执行。

        【讨论】:

        • 是的,我知道如果你重新定义了可能是自递归问题的 init 方法。但是如果你定义另一个方法,比如 initWithCount,从技术的角度来看,我不明白这一点。
        • 类、实例和静态方法是在创建类对象时创建的静态对象。严格来说,没有构造函数创建实例的 OOP 语言——它们只是语法保护的实例方法,需要绑定到在调用时创建并提供给构造函数的实例——这也就是说,当你已经有一个实例可以使用时,没有任何这样的 OOP 语言不允许你在构造函数中访问实例方法。
        猜你喜欢
        • 2013-04-03
        • 2011-04-11
        • 2010-09-16
        • 1970-01-01
        • 1970-01-01
        • 2012-07-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多