声明属性的点符号与消息符号


81

现在,我们对属性使用“点”符号。我见过各种的Forth约点符号主场迎战消息表示法的优点。为了保持答复不变,我不会在问题中以任何方式答复。

您对属性访问的点符号和消息符号有何看法?

请尝试将其重点放在Objective-C上-我将提出的一个偏见是Objective-C是Objective-C,因此您对Java或JavaScript之类的偏好无效。

有效的注释与技术问题(操作顺序,强制转换优先级,性能等),清晰度(结构与对象的性质,优点和缺点),简洁性等有关。

注意,我在严格的代码质量和可读性方面工作过,曾在大型项目中工作过,这些项目的代码约定和质量至关重要(一次编写读取一千次范例)。


14
+1这是一个很好的问题,您将得到很多矛盾的答案。=)
Dave DeLong

1
源代码编辑器应适应程序员的个人喜好,而不更改文件本身的字符。这样,每个人都会得到他们想要的东西。
Arne Evertsson,2010年

Answers:


64

不要将点用于行为。使用点来访问或设置诸如填充之类的属性,通常将属性声明为属性。

x = foo.name; // good
foo.age = 42; // good

y = x.retain; // bad

k.release; // compiler should warn, but some don't. Oops.

v.lockFocusIfCanDraw; /// ooh... no. bad bad bad

对于Objective-C的新手,我建议不要将点号用于声明为@property的东西。一旦对语言有了感觉,就做对的事情。

例如,我发现以下完全自然的现象:

k = anArray.count;
for (NSView *v in myView.subviews) { ... };

您可以期望clang静态分析器具有增加的功能,使您可以检查是否仅将点用于某些模式,而不用于某些其他模式。


18
哇,我什至不知道除了属性之外,您还可以使用点语法。让我惊讶!(但我同意,点仅应用于属性)
jbrennan

13
那是不对的。点表示法是等效方法调用的直接同义词。仅此而已。
bbum

2
我想知道为什么点表示法不限于@property声明的访问器。似乎允许类作者解析应允许使用点表示法的灰色区域,并且是否使用.uppercaseString允许类表示其意图并让其使用的方法似乎并没有那么模棱两可由编译器强制执行。也许我缺少某些东西,需要当前点符号的实现。

4
它可能仅限于此,@property但这都需要API的使用者学习信息的另一个布尔维度,并且API的设计者很可能陷入关于应该和不应该是什么的争论@property。请注意,Xcode@property在完成代码时更喜欢-权重更高的-隐含方法...。鼓励但不强制执行。
bbum 2010年

1
@rodamn确实回答了这个问题;建议@property仅在对语言不熟悉时才将点与声明的访问器一起使用。当人们对使用Objective-C进行编码充满信心时,请做对的事情。有趣; 我们许多人转而使用非常有限的点。
bbum 2014年

22

首先,我要说的是我开始使用Visual / Real Basic进行编程,然后又转向Java,因此相当习惯于点语法。但是,当我最终转向Objective-C并习惯了方括号,然后看到了Objective-C 2.0的引入及其点语法时,我意识到我真的不喜欢它。(对于其他语言,这很好,因为这就是它们的用法)。

在Objective-C中,我有三种主要的带有点语法的内容:

1号牛肉:不清楚为什么会出错。例如,如果我有一行:

something.frame.origin.x = 42;

然后,我将得到一个编译器错误,因为它something是一个对象,并且您不能将对象的结构用作表达式的左值。但是,如果我有:

something.frame.origin.x = 42;

然后编译就很好了,因为它something是一个具有NSRect成员的结构本身,我可以将其用作左值。

如果我采用此代码,则需要花一些时间来弄清楚是什么something。是结构吗?是物体吗?但是,当我们使用方括号语法时,它会更加清晰:

[something setFrame:newFrame];

在这种情况下,是否something存在物体绝对没有歧义。引入歧义是我的第一要务。

Beef#2:在C语言中,点语法用于访问结构的成员,而不是调用方法。程序员可以覆盖对象的setFoo:foo方法,但仍可以通过访问它们something.foo。在我看来,当我看到使用点语法的表达式时,我期望它们是对ivar的简单赋值。 这并非总是如此。 考虑一个介导数组和表视图的控制器对象。如果我致电myController.contentArray = newArray;,我希望它将用新数组替换旧数组。但是,原始程序员可能已经重写setContentArray:,不仅可以设置数组,还可以重新加载tableview。从这一行来看,没有任何迹象表明这种行为。如果我看到[myController setContentArray:newArray];,那么我会想:“啊哈,一种方法。我需要去看看该方法的定义,以确保我知道它在做什么。”

因此,我认为我对Beef#2的总结是,您可以使用自定义代码覆盖点语法的含义。

牛肉#3:我认为它看起来很糟糕。作为一个Objective-C程序员,我已经完全习惯于使用括号括起语法,因此一直阅读并看到漂亮的括号中的一行,然后突然被foo.name = newName; foo.size = newSize;等打断,这对我来说有点分散注意力。我意识到有些东西需要点语法(C结构),但这是我唯一的使用它们的时间。

当然,如果您要自己编写代码,请使用自己喜欢的任何方式。但是,如果您正在编写打算在开源上计划的代码,或者正在编写不希望永久维护的代码,那么我强烈建议您使用括号语法。当然,这只是我的意见。

针对点语法的最新博客文章:http ://weblog.bignerdranch.com/?p= 83

驳斥上述帖子:http ://eschatologist.net/blog/?p=226 (原始文章支持点语法:http ://eschatologist.net/blog/?p=160 )


5
#1牛肉对我来说有点似是而非。除了您尝试向结构发送消息然后必须弄清楚变量实际上是结构之外,我再也没有看到这有什么问题了。实际上,您是否看到很多了解此工作原理的人对此感到困惑?这看起来就像是您一次搞砸了,了解左值的东西,然后在将来正确做的事情-就像说,不要将NSNumbers当作ints对待。
查克(Chuck)

2
@Chuck在某种程度上是一个边缘案例,但是我做了很多合同开发,其中涉及到继承项目并必须与他们合作。 通常 something是一个对象,但是我遇到了几个原始作者在其中创建结构的地方(为了提高速度,降低内存使用量等),我不得不花一些时间来弄清楚代码为什么不行。 t编译。
戴夫·德隆

14

我是一名新的Cocoa / Objective-C开发人员,对此我的看法是:

即使我是从Obj-C 2.0开始的,我仍然坚持使用消息符号,即使点符号是更熟悉的感觉(Java是我的第一语言。)我这样做的原因很简单:我仍然不太清楚为什么他们在语言中添加了点号。对我来说,这似乎是不必要的,“不纯净的”补充。尽管任何人都可以解释它对语言的好处,但我很高兴听到它。

但是,我认为这是一种风格选择,只要它是一致且可读的,就不会有对与错的方式,就像其他任何风格选择一样(例如,将左花括号放在与方法标题或下一行)。


2
+1好答案。我真的很想知道它背后的“原因”。也许bbum或mmalc都知道答案...(它们都在work上工作)
Dave DeLong

11

Objective-C点表示法是一种语法糖,可以转换为正常的消息传递,因此在幕后并没有任何改变,并且在运行时没有任何区别。点表示法绝对不比消息传递快。

在此之后,我需要介绍一些优点和缺点:

点表示法的利弊

  • 优点

    • 可读性:点表示法比嵌套括号按摩传递更易于阅读
    • 它简化了与属性和属性的交互:对于属性使用点符号,对于方法使用消息符号,您可以在synthax级别实现状态和行为的分离
    • 可以使用复合赋值运算符(1)
    • 使用@property和点表示法,编译器可以为您完成很多工作,在获取和设置属性时,它可以生成用于良好内存管理的代码。这就是Apple官方指南建议使用点符号的原因。
  • 缺点

    • 点符号仅允许访问已声明的 @property
    • 由于Objective-C是在标准C(语言扩展)之上的一层,因此如果所访问的实体是对象还是结构,则点表示法实际上并不清楚。通常,您似乎正在访问结构的属性。
    • 用点表示法调用方法会丢失命名参数的可读性
    • 当混合消息表示法和点表示法看起来像您是用两种不同的语言编码时

代码示例:

(1)复合运算符用法代码示例:

//Use of compound operator on a property of an object
anObject.var += 1;
//This is not possible with standard message notation
[anObject setVar:[anObject var] + 1];

7

最好的建议是使用与语言本身一致的语言风格。但是,这不是在OO系统中编写功能代码的情况(反之亦然),而点符号是Objective-C 2.0中语法的一部分。

任何系统都可能被滥用。所有基于C的语言中都存在预处理器,足以完成非常奇怪的事情。如果您需要确切地了解它会变得多么奇怪,只需看混淆C竞赛。这是否意味着预处理器会自动损坏,并且永远不要使用它?

使用点语法访问在接口中已定义的属性很容易受到滥用。潜在的滥用行为不一定是反对它的理由。

财产使用可能会有副作用。这与用于获取该属性的语法正交。CoreData,委派,动态属性(first + last = full)都必须在后台进行某些工作。但这将使“实例变量”与对象的“属性”混淆。没有理由为什么必须必须按原样存储属性,特别是如果可以计算属性(例如,字符串的长度)。因此,无论您使用foo.fullName还是[foo fullName],仍将进行动态评估。

最后,该属性的行为(当用作 左值时)由对象本身定义,例如是否复制副本或保留副本。这使得以后在属性定义本身中更改行为变得更容易,而不是必须重新实现方法。这增加了该方法的灵活性,从而导致发生更少(实施)错误的可能性。仍然有可能选择错误的方法(即复制而不是保留),但这是体系结构而不是实现问题。

最终,它归结为“看起来像结构吗”的问题。这可能是迄今为止辩论的主要区别所在。如果您有一个结构,它的工作原理不同于您有一个对象。但这始终是事实。您无法发送struct消息,并且需要知道它是基于堆栈还是基于引用/ malloc。已经有心理模型在用法上有所不同([[[CGRect alloc] init]或struct CGRect?)。在行为方面,它们从未统一过。您需要了解每种情况下要处理的内容。为对象添加属性表示不太可能会使任何知道其数据类型的程序员感到困惑;如果不这样做,就会遇到更大的问题。

至于一致性;(Objective-)C在自己内部是不一致的。根据源代码中的词汇位置,=既用于赋值又用于相等。*用于指针和乘法。BOOL是字符,而不是字节(或其他整数值),尽管YES和NO分别为1和0。一致性或纯正性不是该语言设计的目的;这是关于把事情做好。

因此,如果您不想使用它,请不要使用它。用另一种方式完成它。如果您想使用它并且了解它,那么使用它就可以了。其他语言处理通用数据结构(映射/结构)和对象类型(具有属性)的概念,尽管一种语言仅仅是数据结构而另一种是富对象,但它们经常使用相同的语法。即使不是您的首选,Objective-C中的程序员也应具有处理所有样式的同等功能的能力。


6

我将其用于属性,因为

for ( Person *person in group.people){ ... }

比阅读起来容易一点

for ( Person *person in [group  people]){ ... }

在第二种情况下,通过将大脑置于消息发送模式而中断了可读性,而在第一种情况下,很明显,您正在访问组对象的people属性。

例如,在修改集合时,我还将使用它:

[group.people addObject:another_person];

比...更具可读性

[[group people] addObject:another_person];

在这种情况下,重点应放在将对象添加到数组而不是链接两个消息的操作中。


5

我在Objective-C 2.0时代已经长大,我更喜欢点符号。对我来说,它可以简化代码,而不必使用多余的括号,而只能使用一个点。

我还喜欢点语法,因为它使我感觉好像我正在访问对象的属性,而不是仅向其发送消息(当然,点语法确实可以转换为消息发送,但出于外观考虑,点的感觉就不同了)。确实没有像通过旧语法“调用吸气剂”那样,而是感觉好像我直接从对象中得到了有用的东西。

关于此的一些辩论涉及“但是我们已经有了点句法,它是用于structs!”的。没错 但是(再说一次,这只是心理上的)对我来说基本上是一样的。使用点语法访问对象的属性与访问结构的成员的感觉相同,这或多或少具有预期的效果(我认为)。

****编辑:正如bbum所指出的,您还可以使用点语法来调用对象上的任何方法(我不知道这一点)。因此,我会说,我对点语法的看法仅用于处理对象的属性,而不是用于每天发送消息**


3

我非常喜欢消息传递语法...但是仅仅是因为这是我学到的。考虑到我的很多类以及不是Objective-C 1.0风格的类,我不想将它们混合在一起。除了“我已经习惯了”之外,我没有任何不使用点语法的真正原因...除此之外,这使我疯狂

[myInstance.methodThatReturnsAnObject sendAMessageToIt]

我不知道为什么,但是没有任何理由,这确实让我很生气。我只是认为

[[myInstance methodThatReturnsAnObject] sendAMessageToIt]

更具可读性。但每一个他自己!


3
我会不时这样做,但前提是要访问一个属性。例如:[self.title lowercaseString]或什么。但是从样式上我可以看到为什么混合和匹配语法很麻烦。我这样做的唯一原因是保持属性是什么以及返回对象的方法是什么(我知道属性实际上就是这样,但是希望您能理解我的意思)。
jbrennan

3

老实说,我认为这取决于风格。我个人反对点语法(尤其是在发现您可以将其用于方法调用而不仅仅是读取/写入变量之后)。但是,如果要使用它,我强烈建议您不要将其用于访问和更改变量以外的其他用途。


3

面向对象编程的主要优点之一是,不能直接访问对象的内部状态。

在我看来,点语法是一种尝试,使它的外观和感觉好像直接在访问状态。但实际上,这只是-foo和-setFoo:行为的语法糖。我自己,我更喜欢用铁锹叫铁锹。点语法在一定程度上简化了代码的可读性,但并不能帮助理解,因为不能记住您实际上在调用-foo和-setFoo:可能会带来麻烦。

在我看来,综合访问器似乎是一种尝试,使其易于编写直接访问状态的对象。我的信念是,这完全可以鼓励创建面向对象程序设计避免的程序设计。

总而言之,我宁愿从未引入点语法和属性。我曾经能够告诉人们,ObjC是对C的一些干净扩展,使其更像Smalltalk,但我认为这不再是真的。


2

在我看来,点语法使Objective-C的Smalltalk风格更少。它可以使代码看起来更简单,但增加了歧义。它是一个structunion或对象?


2

许多人似乎将“属性”与“实例变量”混在一起。我认为,属性的要点是可以修改对象而不必知道其内部。在大多数情况下,实例变量是属性的“实现”(而属性又是“接口”),但并非总是这样:有时,属性并不对应于ivar,而是计算返回值“即时”。

这就是为什么我认为“点语法会欺骗您以为您正在访问变量,从而造成混乱”的想法是错误的。点或方括号,您不应对内部结构做任何假设:它是属性,而不是ivar。


附带说明一下,Objective-C对象引用不是直接的C结构变量,而是更像“结构的指针”,因此点语法对直接访问成员没有意义;正是箭头操作符->扮演了这个角色(当然,无论何时说ivars都不受访问限制)。
Nicolas Miari 2015年

1

我想我可能会改用消息传递而不是点表示法,因为在我的头中object.instanceVar只是属于object的instanceVar,对我而言,它根本不像方法调用那样,因此,可能会发生一些事情在访问器中,无论您使用instanceVar还是self.instanceVar都可能比仅隐式与显式有更多不同。只是我的2美分。


1

点表示法试图使消息看起来像是对结构成员的访问,而实际上并非如此。在某些情况下可能效果不错。但是很快有人会想到这样的事情:

NSView *myView = ...;
myView.frame.size.width = newWidth;

看起来不错 但是不是。和...一样

[myView frame].size.width = newWidth;

这不起作用。编译器接受第一个,但是正确地接受第二个。即使它最初发出了错误或警告,这也很令人困惑。


1

叫我懒,但是如果我必须输入一个'。每次使用两个[]来获得相同的结果,我希望使用一个。我讨厌冗长的语言。Lisp中的()使我发疯。诸如数学之类的优美语言简洁而有效,其他所有语言均达不到要求。


1
问题是数学虽然简洁有效,但不是一门常规语言,因此我们无法对其进行分析和编译。请注意,例如,在数学函数中,通常在括号中写上括号,因为如果没有括号,将很难理解。
jbrennan

1

使用点表示法(只要有可能)

在实例方法上返回一些值

不要使用点符号

在实例方法返回void时,在init方法或Class方法中。

我个人最喜欢的例外

NSMutableArray * array = @[].mutableCopy;

0

我个人在代码中根本不使用点符号。仅在需要时在CoreData KVC绑定表达式中使用它。

对我而言,未在代码中使用它们的原因是点符号隐藏了setter的语义。无论setter语义(assign / retain / copy)如何,以点符号设置属性总是看起来像分配。使用消息符号可以看到接收对象可以控制设置程序中发生的事情,并强调了需要考虑这些影响的事实。

我仍在考虑检索KVC兼容或声明的属性的值时是否要使用点符号,因为它显然更紧凑,更易读并且没有隐藏的语义。现在,为了保持一致性,我坚持使用消息符号。


1
可能仍然存在隐藏的事情。一个getter可以做其他事情,而不仅仅是返回一个实例变量。即使它是一个声明的属性,也不必合成getter或将其重写为子类。
斯文

-1

好的,Objective-C中的点符号确实很奇怪。但是,如果没有它,我仍然无法做到以下几点:

int width = self.frame.size.width;

工作正常,但是:

int height = [[[self frame] size] height];

给我“无法转换为指针类型”。不过,我真的很想让我的代码与消息符号保持一致。


5
-frame返回NSRect,它是C结构,而不是Objective-C对象。这就是第二个示例导致编译器错误的原因。它应该是:int height = [自身框架] .size.height;

1
同意 但是括号后面的圆点看起来糟透了!我通常首先将rect存储在本地变量中。
Nicolas Miari 2012年

-2

这是一个很好的问题,我对此有很多不同的答案。尽管许多人都谈到了这些主题,但我将尝试从另一个角度回答这个问题(有些人可能暗中做了):

如果我们使用“点”符号,则该方法的目标分辨率在编译时完成。如果我们使用消息传递,则目标的解析将推迟到运行时执行。如果在编译时解析目标,则执行速度会更快,因为在运行时解析目标会产生一些开销。(并不是时差会很重要)。由于我们已经在对象的接口中定义了属性,因此在运行时将目标的分辨率与属性的分辨率区分开是没有意义的,因此点符号表示我们应使用该符号来访问属性。


您是否知道在ObjectiveC中选择器在任何情况下都会在运行时进行评估,解析和调用?因此,点符号是旧括号样式的纯同义词。没有任何技术差异。您的速度假设是完全错误的-尝试一下,使用乐器,然后看看自己。
直到2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.