【问题标题】:When to use instance variables and when to use properties何时使用实例变量以及何时使用属性
【发布时间】:2012-05-13 00:44:17
【问题描述】:

在使用 Objective-C 属性时,您是否可以完全停止创建实例变量,或者显式实例变量(不是由属性合成的实例变量)仍然用于属性不合适的用途?

【问题讨论】:

    标签: objective-c ios cocoa instance-variables


    【解决方案1】:

    这个问题在here之前已经解决了

    当您使用synthesize 时,会为您处理和实例化实例变量。如果您在新版本的 XCode 中使用 Lion,还请查看 ARC 中的各种属性in Transitioning to ARC

    【讨论】:

    • 我不认为这是同一个问题,但我更新了我的问题,希望能更清楚。
    【解决方案2】:

    您始终可以从外部访问属性。因此,如果您只想从类内部读取变量,您仍然必须声明 iVar。使用object->ivar 访问公共 ivar 也比使用方法调用稍快。

    【讨论】:

    • 这不是真的。如果您在 .m 文件中声明该属性怎么办?
    • 没错,您可以完全隐藏该属性,但不能从您的 m 文件外部访问它,例如子类。
    • @Martin:由于该属性是作为一对方法实现的,因此无论在何处声明,它始终在运行时可用。
    • @Martin:你不知道哪一部分?属性实际上是 setter 和 getter 方法,还是方法总是有效地公开?
    • 虽然使用-> 直接获取内部 ivars 比 setter 更快,但它几乎永远不是正确的答案。当您进行这种优化时,您几乎总是应该进行更好的优化。这是一种非常危险的技术,不适合一般使用。
    【解决方案3】:

    你能完全停止创建实例变量吗

    不,你不能(在某种意义上)。如果您有属性,您可以做的是停止声明它们。如果您合成了一个属性并且您没有声明 instvar,它将为您声明,因此您正在创建一个实例变量,而不是显式地。

    它们是否仍然用于属性不合适的目的?

    它曾经是为所有内容创建属性的建议,因为合成属性会为您完成几乎所有的保留和释放。然而,对于 ARC,使用属性来包装内存管理的理由已经消失。现在(对于 ARC)的建议是,我相信,使用属性来声明您的外部接口,但使用直接实例变量,其中变量是对象内部状态的一部分。

    这是采用 ARC 的一个很好的理由:属性恢复到它们的真正目的,只是作为类 API 的一部分,并且不再需要将它们用作隐藏内存管理工作的骇人听闻的方式。

    编辑

    还有一件事:您现在可以在@implementation 中声明实例变量,因此现在无需在@interface 中泄露任何实现细节。即

    @implementation MyClass
    {
        NSString* myString;
    }
    // method definitions
    @end
    

    而且我很确定它也适用于类别。 - 请参阅下面的评论

    【讨论】:

    • 您不能将 ivars 和属性添加到类别,因为 objc-runtime 只允许在类注册期间添加 ivars。在向运行时注册后,您无法更改类的内存布局。
    • 可以,但是将 ivars 添加到类扩展中(密切相关,但不同于类别)
    • @Jonathan Cichon:谢谢你,刚刚试了一下,结果你对实例变量是正确的,但对属性是错误的。您可以添加属性,但不能@synthesize 它们。
    • @JonathanCichon,类别中的非综合属性非常有用且常见。你只需要编写一个自定义的 getter/setter。有关此技术的最常见用法,请参阅此博客文章:oleb.net/blog/2011/05/…
    • @Jonathan Cichon:恐怕这是对属性的误解。属性是 API 的一部分,实现取决于您,@synthesize 只是通过添加一组标准访问器来自动化最常见的实现模式之一。没有什么可以阻止您定义自己的不同访问器。
    【解决方案4】:

    我建议将所有内容都声明为属性并完全避免手动 ivars。手动创建 ivars 并没有真正的好处。在标题 @interface 中声明公共属性,在 .m 文件的私有类扩展中声明私有属性。

    对于 JeremyP 的某些观点,在 ARC 下,访问器的内部使用仍然具有重要价值,尽管内存管理不再是一个重要问题。它确保 KVO 正常工作,更好地子类化,支持自定义 setter(特别是像 NSTimer 这样的东西),支持自定义 getter(例如延迟实例化)等。混合使用访问器和 ivars 非常容易出错.忘记您需要以哪种方式访问​​哪个太容易了。一致性是好的 ObjC 的标志。

    如果您出于某种原因绝对必须声明一个 ivar,那么您应该按照 JeremyP 的说明在 @implementation 块中进行声明。


    更新(2013 年 10 月):

    Apple's guidance(来自 Objective-C 编程:封装数据):

    大多数属性都由实例变量支持

    一般来说,您应该使用访问器方法或点语法进行属性访问,即使您是从其自己的实现中访问对象的属性,在这种情况下您应该使用self

    ...

    此规则的例外是在编写初始化、解除分配或自定义访问器方法时,如本节后面所述。

    【讨论】:

    • KVO 对于内部的东西并不重要。子类化也不是。任何属于类实现的部分都不应泄漏,即使是子类也是如此。这是良好 OOP 的标志。
    • KVO(尽管偶尔使用自我观察),因为您经常需要私有属性的访问器(延迟实例化、线程安全等),并且使用它们既简单又便宜,您应该除非有充分的理由不使用它们(即 dealloc),否则总是使用它们。有时使用 ivars 有时使用访问器很容易出错,并且难以检查其正确性。
    • 如何在没有实例变量的情况下进行惰性实例化?我再说一遍:Apple 列表中报告的官方说法是,当你有 ARC 时,使用实例变量作为内部状态,但如果你使用传统的引用计数,则对所有内容使用属性。
    • @JeremyP,只是好奇,苹果文档在哪里?
    • @Alex311 我认为我从未见过任何来自 Apple 的官方消息。我所指的文档是 Apple 员工发给 Objective-C 列表的电子邮件。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-04-13
    • 1970-01-01
    • 2018-05-29
    • 2011-02-22
    • 2011-06-07
    • 1970-01-01
    相关资源
    最近更新 更多