Objective-C:属性与 iVars

一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / Java 学习路线 / 一对一提问 / 学习打卡/ 赠书活动

目前,正在 星球 内带小伙伴们做第一个项目:全栈前后端分离博客项目,采用技术栈 Spring Boot + Mybatis Plus + Vue 3.x + Vite 4手把手,前端 + 后端全栈开发,从 0 到 1 讲解每个功能点开发步骤,1v1 答疑,陪伴式直到项目上线,目前已更新了 204 小节,累计 32w+ 字,讲解图:1416 张,还在持续爆肝中,后续还会上新更多项目,目标是将 Java 领域典型的项目都整上,如秒杀系统、在线商城、IM 即时通讯、权限管理等等,已有 870+ 小伙伴加入,欢迎点击围观

我认为如果它是关于从类外部获取/设置一些数据(正确的,应该使用属性),那么这个主题就不那么有争议了。所以在这篇文章中,我们将重点关注私有和受保护的类成员。

有关系吗?

这听起来可能没那么重要——为什么我们不能随意做出决定并坚持下去呢?好吧,properties / ivars 是一直被使用的东西。我认为有时关注我们如何执行常见任务是一种很好的做法。这是很自然的,也是提高效率的好方法——即使是轻微的改进也会在一段时间内产生相当大的影响。

表现

显然,使用属性会消耗一些 CPU,因为会调用其他方法。但这在99.99%的情况下都是微不足道的!对于其余的 0.01%——使用 ivars,但请注意,与您通常可以添加的其他优化相比,您获得的改进几乎没有。

属性

属性有属性,它们非常有用。但是,我认为它们只有在课外使用时才有用。让我们讨论其中的两个:

  • readonly – 只读属性意味着它只能由实例设置。为了有用,实例应该在代码中至少设置一次。这意味着您实际上必须写入 ivar。 (有一个例外:您可以在没有 ivar 的情况下实现一个只读属性,但这只是一种方法,不需要 @property 行。)因此,如果您只访问一次 ivar,为什么不在所有地方都使用它呢?
  • 复制——有时,你必须复制一些东西——将可变的转换为不可变的或保存一个块。但是对私有属性使用复制属性实际上不会使您的代码更具可读性。如果需要的话,我更喜欢在赋值之前调用复制方法。

如果您在类中使用 ivar / property,您通常知道它的用途是什么以及应该如何访问它。所以我认为属性不会添加任何有利于私有属性的内容。

用自定义实现替换 Getters/Setters

我曾在一个约定不使用 ivars 的团队工作过一次。不要误会我的意思——代码约定通常是一件好事,我只是不同意我对此的主要原因之一:“如果需要,我们可以稍后覆盖默认的 getter/setter”。来吧,你多久覆盖一次内部属性 getter/setter?而且,重构几乎不需要时间,因为所有的用法都在同一个文件中。

访问控制

受保护的成员呢?在目标 C 中,有实例变量的访问控制,但没有方法。一旦你定义了一个方法(或属性),它就可以从任何地方调用(访问),所以理论上只有公共属性。但在我看来,在 .m 中定义一个属性以将其视为私有就足够了。如果你需要保护怎么办?有一个技巧:对于类 SomeClass,您定义一个额外的 .h 文件,将其命名为 SomeClass_protected.h,并将所有受保护的属性放在那里。这有点难看,但这种情况实际上很少见,至少对我而言(我个人认为使用继承更频繁地带来麻烦是有帮助的,而且我会使用它的情况真的很少)。

另一方面,通过使用属性,您可以轻松地在公共和私有之间切换它们(就像已经提到的那样,使用公共 ivars 是非常糟糕的)。在公共和私有之间切换的需要值得怀疑,如果在属性和 ivars 之间切换,重构并不难,但不得不说它掩盖了我的偏见:-)。

四通八达的交通网络

就个人而言,我很确定谁是这里的赢家。让我们看看下面的例子:


 [listCopy addObject:self.nextEntry];
_list = listCopy.copy;

查看 nextEntry 和列表​​。什么是公共的,什么是私人的?虽然 self.nextEntry 是一个属性,但它是私有的——但在检查定义之前您无法知道它!那么 _list 呢?它实际上是一个公共但只读的属性,因此我们通过它的 ivar 访问它以分配一个新值。

我认为这很令人困惑。虽然您可能对 _list 无能为力,但对内部成员使用 ivars 至少会改善我们使用 nextEntry 的情况。它将被称为 _nextEntry,在大多数情况下,这意味着它是私有的。

您当然可以在私有属性中使用 _ 来克服它,尽管我认为我从未见过有人以这种方式使用私有属性。要么这个问题不困扰人们,要么可能是那些被这个问题困扰的人只是使用ivars。

ARC 之前的疼痛

到目前为止,似乎没有比使用私有属性更好的方法了。那为什么开发者要使用它们呢?我认为唯一的原因是非 ARC 历史。在 ARC 之前,您必须保留-释放类中引用的每个对象。私人财产正在解决它真的很好!代替


 [listCopy addObject:self.nextEntry];
_list = listCopy.copy;

你会写:


 [listCopy addObject:self.nextEntry];
_list = listCopy.copy;

试想一下,如果 ARC 从一开始就存在会发生什么。任何开始使用 Objective C 编程的人都会像在其他语言中一样使用 ivars,因此使用私有属性永远不会成为如此流行的做法。好多了,对吧?