【问题标题】:Should I use properties or direct reference when accessing instance variables internally?在内部访问实例变量时应该使用属性还是直接引用?
【发布时间】:2011-04-14 18:22:51
【问题描述】:

假设我有这样的课程:

@interface MyAwesomeClass : NSObject
{
@private
    NSString *thing1;
    NSString *thing2;
}
@property (retain) NSString *thing1;
@property (retain) NSString *thing2;
@end

@implementation MyAwesomeClass
@synthesize thing1, thing1;
@end

当访问thing1thing2内部(即在MyAwesomeClass的实现中),是使用属性更好,还是直接引用实例变量(假设情况其中我们不在“自定义”访问或修改器中做任何工作,即我们只是设置和获取变量)。 Pre-Objective C 2.0,我们通常只是直接访问 ivars,但现在通常的编码风格/最佳实践是什么?如果实例变量/属性是私有的并且在类之外根本无法访问,那么这个建议会改变吗?您应该为每个 ivar 创建一个属性,即使它们是私有的,还是仅用于面向公众的数据?如果我的应用不使用键值编码功能(因为 KVC 仅触发属性访问)怎么办?

我感兴趣的是超越底层技术细节。例如,给定(次优)代码,如:

@interface MyAwesomeClass : NSObject
{
    id myObj;
}
@proprety id myObj;
@end

@implementation MyAwesomeClass
@synthesize myObj;
@end

我知道myObj = anotherObject 在功能上与self.myObj = anotherObj 相同。

当然,属性不仅仅是指示编译器为您编写访问器和修改器的花哨的语法;它们也是一种更好地封装数据的方法,即,您可以更改类的内部实现,而无需重写依赖这些属性的类。在处理类自己的 internal 代码时,我对解决此封装问题重要性的答案感兴趣。此外,正确编写的属性可以触发 KVC 通知,但直接 ivar 访问不会;如果我的应用现在不使用 KVC 功能,以防万一将来可能使用,这是否重要?

【问题讨论】:

    标签: objective-c oop


    【解决方案1】:

    这里提到的其他事情都没有问题。其他答案遗漏的几件事是:

    首先,始终牢记访问器/修改器是虚拟的含义(就像所有的 Objective-C 方法一样。)一般来说,有人说应该避免在 init 和 dealloc 中调用虚拟方法,因为你不需要知道子类会做什么,这可能会搞砸你。出于这个原因,我通常尝试直接在 init 和 dealloc 中访问 iVar,并通过其他任何地方的访问器/修改器访问它们。另一方面,如果您没有在所有其他地方始终如一地使用访问器,则覆盖它们的子类可能会受到影响。

    如果您在 init 和 dealloc 之外的任何位置直接访问 iVar,则无法为任何人维护属性的原子性保证(即您的 @properties 被声明为原子)。如果您需要一些原子性,请不要通过直接访问 iVar 来丢弃原子性。同样,如果您不需要这些保证,请将您的属性声明为非原子的(为了性能)。

    这也与 KVO 问题有关。在 init 中,没有人可能(合法地)观察你,而在 dealloc 中,任何剩余的观察者都有一个过时的未保留(即虚假)引用。同样的推理也适用于属性的原子性保证。 (即在 init 返回之前并发访问如何发生,而在 dealloc 期间发生的访问本质上是错误。)

    如果你混合和匹配直接和访问器/修改器的使用,你可能不仅会与 KVO 和原子性发生冲突,还会与子类发生冲突。

    【讨论】:

      【解决方案2】:

      如果thing1 与 KVO 一起使用,最好在设置时使用self.thing1=。如果thing1@public,那么最好假设有一天有人会想将它与KVO 一起使用。

      如果thing1 具有复杂的集合语义,您不想在设置它的任何地方重复(例如retain,或非nonatomic),那么使用self.thing1= 是个好主意。

      如果基准测试显示调用 setThing1: 需要花费大量时间,那么您可能需要考虑在不使用 self.thing1= 的情况下设置它的方法——也许请注意它不能被 KVO 处理,或者看看是否手动实现KVO 更好(例如,如果您在某个循环中设置了 3000 次,您可能可以通过 self->thing1 设置它 3000 次,并针对即将更改和已更改的值进行 2 次 KVO 调用)。

      这就留下了在你知道你没有使用 KVO 的私有变量上的一个简单的 setter 的情况。到那时,它不再是一个技术问题,而是属于代码风格。至少只要访问器没有在分析器中显示为瓶颈。那时我倾向于使用直接 ivar 访问(除非我认为我将来会 KVO 该值,或者可能希望将其公开并因此认为其他人可能想要 KVO)。

      但是,当我使用直接 ivar 访问设置内容时,我尝试仅通过 self->thing1= 进行设置,这样可以更轻松地找到所有内容并在我发现需要使用 KVO 时进行更改,或者制作它public,或者制作更复杂的访问器。

      【讨论】:

        【解决方案3】:

        我认为没有任何方法是“更好”的。您会看到这两种样式都很常用,因此现在甚至没有通常/最佳实践。以我的经验,所使用的风格对我消化一些我正在寻找的实现文件的影响很小。在查看其他人的代码时,您当然希望对这两种风格(以及两者之间的任何一种风格)感到满意。

        在维护方面,为每个内部 ivar 使用一个属性可能有点过火。我已经完成了,它增加了我认为不会为我带来回报的大量工作。但是,如果您有强烈的愿望/强迫症,希望在任何地方都能看到像self.var 这样的一致代码,并且每次看课程时都会在脑海中浮现它,那么请使用它。不要小看唠叨的感觉对工作效率的影响。

        例外 - 显然,对于自定义 getter(例如惰性创建),您没有太多选择。此外,我确实会为内部设置器创建和使用属性,因为它更方便(例如,设置具有所有权语义的对象)。

        “以防万一”、“可能”不是在没有更多数据的情况下做某事的令人信服的理由,因为实现它所需的时间是非零的。一个更好的问题可能是,某个类中的所有私有 ivars 将来需要 KVC 通知但现在不需要的概率是多少?对于我自己的大多数类,答案都非常低,所以我现在避免为每个私有 ivar 创建属性的硬性规则。

        我发现在处理内部实现时,我很快就能很好地掌握应该如何访问每个 ivar。

        如果你有兴趣,我自己的做法是这样的:

        • 读取 ivars:直接访问,除非有自定义 getter(例如惰性创建)
        • 写ivars:直接在alloc/dealloc。在其他地方,通过私有财产(如果存在)。

        【讨论】:

          【解决方案4】:

          如果您花时间在 cocoa-dev 邮件列表上,您会发现这是一个非常有争议的话题。

          有些人认为 ivars 应该只在内部使用,而属性不应该(或很少)在外部使用。 KVO 通知和访问器副作用存在各种问题。

          有些人认为您应该始终(或大部分)使用属性而不是 ivars。这里的主要优点是您的内存管理很好地包含在访问器方法中,而不是散布在您的实现逻辑中。可以通过创建指向相同 ivar 的单独属性来克服 KVO 通知和访问器副作用。

          查看 Apple 的示例代码会发现它们在这个主题上无处不在。一些样本在内部使用属性,一些使用 ivars。

          我会说,总的来说,这是一个品味问题,没有正确的方法可以做到这一点。我自己混合使用了这两种风格。

          【讨论】:

            【解决方案5】:

            thing1 = something;self.thing1 = something; 赋值的唯一区别是,如果你想对赋值对象进行属性赋值操作(retaincopy 等),那么你需要使用属性。没有属性的分配实际上就是分配对提供的对象的引用

            我认为没有必要为内部数据定义一个属性。只为将经常访问并需要特定的 mutator 行为的 ivars 定义属性。

            【讨论】:

              猜你喜欢
              • 2015-12-03
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-06-06
              • 1970-01-01
              • 2017-06-30
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多