objective-c - 为什么要使用 ivar?

标签 objective-c ios memory-management key-value-observing ivar

我通常看到这个问题是用另一种方式问的,比如 Must every ivar be a property? (我喜欢 bbum 对这个问题的回答)。

我几乎只在我的代码中使用属性。然而,每隔一段时间,我就会与一个长期在 iOS 上进行开发并且是传统游戏程序员的承包商一起工作。他编写的代码几乎不声明任何属性,并且依赖于 ivars。我认为他这样做是因为 1.) 他已经习惯了,因为在 Objective C 2.0(07 年 10 月)和 2.) 之前并不总是存在属性,因为不通过 getter/setter 的性能增益最小。

虽然他编写的代码不会泄漏,但我仍然希望他使用属性而不是 ivars。我们讨论过它,他或多或少认为没有理由使用属性,因为我们没有使用 KVO,而且他在处理内存问题方面经验丰富。

我的问题更多......你为什么要使用 ivar 时期 - 有没有经验。使用 ivar 是否真的有那么大的性能差异是合理的?

另外,作为澄清点,我根据需要覆盖 setter 和 getter,并在 getter/setter 中使用与该属性相关的 ivar。但是,在 getter/setter 或 init 之外,我总是使用 self.myProperty 语法。


编辑 1

我感谢所有好的回应。我想解决的一个似乎不正确的问题是,使用 ivar,您可以在使用属性的情况下获得封装。只需在类延续中定义属性。这将向外界隐藏属性(property)。您还可以在接口(interface)中声明属性 readonly 并在实现中将其重新定义为 readwrite ,如:

// readonly for outsiders
@property (nonatomic, copy, readonly) NSString * name;

并在类里面继续:

// readwrite within this file
@property (nonatomic, copy) NSString * name;

要让它完全“私有(private)”,只需在类延续中声明它。

最佳答案

封装

如果 ivar 是私有(private)的,那么程序的其他部分就无法轻松获取它。有了声明的属性,聪明的人就可以很容易地通过访问器访问和改变。

性能

是的,这在某些情况下会有所不同。有些程序有一些限制,他们不能在程序的某些部分使用任何 objc 消息传递(想想实时)。在其他情况下,您可能希望直接访问它以提高速度。在其他情况下,这是因为 objc 消息传递充当优化防火墙。最后,它可以减少您的引用计数操作并最大限度地减少峰值内存使用量(如果操作正确)。

非平凡类型

示例:如果您有 C++ 类型,则直接访问有时只是更好的方法。该类型可能不可复制,或者复制起来可能并不简单。

多线程

您的许多 ivars 是相互依赖的。您必须确保多线程上下文中的数据完整性。因此,您可能倾向于直接访问关键部分中的多个成员。如果您坚持使用访问器来获取相互依赖的数据,那么您的锁通常必须是可重入的,并且您通常最终会进行更多的获取(有时明显更多)。

程序正确性

由于子类可以覆盖任何方法,您最终可能会发现写入接口(interface)与适当管理您的状态之间存在语义差异。程序正确性的直接访问在部分构造的状态中尤其常见——在您的初始化程序和 dealloc 中,最好使用直接访问。您可能还会在访问器、便利构造函数、copymutableCopy 和归档/序列化实现的实现中发现这很常见。

随着人们从所有东西都有一个公共(public)的读写访问器的思维方式转变为一种很好地隐藏其实现细节/数据的思维方式,这种情况也更加频繁。有时您需要正确地绕过子类覆盖可能引入的副作用,以便做正确的事情。

二进制大小

当您考虑程序的执行时,默认情况下声明所有内容为 readwrite 通常会导致许多您永远不需要的访问器方法。所以它会给你的程序和加载时间增加一些脂肪。

最大限度地降低复杂性

在某些情况下,完全没有必要为一个简单的变量添加+类型+维护所有额外的脚手架,例如用一种方法写入并用另一种方法读取的私有(private) bool。


这并不是说使用属性或访问器不好 - 每个都有重要的好处和限制。像许多 OO 语言和设计方法一样,您还应该支持在 ObjC 中具有适当可见性的访问器。有时你需要偏离。出于这个原因,我认为通常最好限制对声明 ivar 的实现的直接访问(例如声明它 @private)。


重新编辑 1:

我们大多数人都已经记住了如何动态调用隐藏的访问器(只要我们知道名称……)。同时,我们中的大多数人没有记住如何正确访问不可见的 ivars(除了 KVC)。类延续有帮助,但它确实引入了漏洞。

这个解决方法很明显:

if ([obj respondsToSelector:(@selector(setName:)])
  [(id)obj setName:@"Al Paca"];

现在只用 ivar 试试,不用 KVC。

关于objective-c - 为什么要使用 ivar?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9086736/

相关文章:

ios - 插入一个数组会影响另一个数组吗?

ios - 在大型 NSDictionary 中查找最小值和对应的键

ios - Protobuf数据在swift中反序列化错误

ios - 如何更好地优化 iOS 上的网络?

c - 如果不断增加访问内存超过 malloc() 分配的大小,linux glibc 中会发生什么

objective-c - iOS : how to reduce size of large PNG files

ios - 显示模态 Controller 时与呈现 Controller 交互

ios - 单击按钮时在 UITableViewCell 中添加/删除 subview 和约束

c++ - 静态函数内部的动态内存分配

c++ - 初始化 3d 数组的快速方法 (C++)