声明属性的点表示法与消息表示法

时间:2009-08-08 17:14:16

标签: objective-c syntax coding-style

我们现在有属性的“点”符号。关于点符号与消息符号的优点,我见过各种backforths。为了保持反应不受影响,我不会在问题中做出任何回应。

您对点符号与财产访问的消息符号有何看法?

请尽量将注意力集中在Objective-C上 - 我提出的一个偏见是Objective-C是Objective-C,所以你喜欢Java或JavaScript是无效的。

有效的评论是关于技术问题(操作顺序,演员优先,表演等),清晰度(结构与对象性质,赞成和反对!),简洁等等。

请注意,我是一个严格的质量和代码可读性的学校,曾参与过代码约定和质量至关重要的大型项目(写入曾经读过一千次范式)。

18 个答案:

答案 0 :(得分:64)

不要将dot用于行为。使用点来访问或设置类似属性的属性,通常是声明为属性的属性。

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的人,我建议不要使用dot作为声明为@property的东西。一旦你对语言有了感觉,那就做正确的事。

例如,我发现以下内容非常自然:

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

你可以期望clang静态分析仪能够让你检查点是仅用于某些模式还是不用于某些其他模式。

答案 1 :(得分: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是对象,则绝对没有歧义。歧义的引入是我的牛肉#1。

牛肉#2:在C中,点语法用于访问结构的成员,而不是调用方法。程序员可以覆盖对象的setFoo:foo方法,但仍然可以通过something.foo访问它们。在我看来,当我使用点语法看到表达式时,我希望它们能够简单地分配到ivar中。 情况并非总是如此。考虑一个调解数组和tableview的控制器对象。如果我调用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

答案 2 :(得分:14)

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

我坚持使用消息符号,即使我开始使用Obj-C 2.0,尽管点符号更为熟悉(Java是我的第一语言。)我的理由非常简单:我仍然不喜欢要明白为什么他们将点符号添加到语言中。对我来说,这似乎是一种不必要的“不纯”的补充。虽然如果有人能解释它对语言的好处,我会很高兴听到它。

然而,我认为这是一种风格选择,我认为没有正确或错误的方式,只要它是一致的和可读的,就像任何其他风格选择一样(如将您的左大括号放在与方法标题或下一行相同的行上。

答案 3 :(得分:11)

Objective-C点符号是一种语法糖,它被转换为正常的消息传递,因此在引擎盖下不做任何改变,并且在运行时没有任何区别。 点符号绝对不比邮件传递快。

在此之后需要的小序言中,我看到了它的优点和缺点:

点符号的利弊

  • <强>优点

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

    • 仅允许使用点表示法访问声明的@property
    • 由于Objective-C是一个高于标准C(语言扩展)的层,因此点符号并不能确定所访问的实体是对象还是结构。通常,看起来您正在访问结构的属性。
    • 使用点符号调用方法会丢失named parameters可读性优势
    • 当混合信息符号和点符号看起来像是用两种不同语言编码时

代码示例:

(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];

答案 4 :(得分:7)

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

任何系统都可能被滥用。所有基于C语言的预处理器的存在足以做出非常奇怪的事情;如果您需要确切了解它可以获得多么奇怪,请查看Obfuscated C Contest。这是否意味着预处理器自动坏了,你永远不应该使用它?

使用点语法访问已在界面中定义的属性,可能会被滥用。潜在滥用的存在不一定是反对它的论据。

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

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

归根结底,它归结为'它看起来像一个结构'问题。到目前为止,这可能是辩论的主要区别;如果你有一个结构,它的工作方式与你有一个对象的方式不同。但这一直是真的;你不能发送一个结构消息,你需要知道它是基于堆栈还是基于reference / malloc。已有的心理模型在使用方面有所不同([[CGRect alloc] init]或struct CGRect?)。他们从未在行为方面统一;你需要知道在每种情况下你正在处理什么。为对象添加属性表示不太可能混淆任何知道其数据类型的程序员;如果他们不这样做,他们就会遇到更大的问题。

至于一致性; (目标 - )C本身不一致。 =基于源代码中的词法位置,用于赋值和相等。 *用于指针和乘法。 BOOL是字符,而不是字节(或其他整数值),尽管是和NO分别为1和0。一致性或纯度不是语言的设计目标;这是关于完成任务。

因此,如果您不想使用它,请不要使用它。以不同的方式完成它。如果你想使用它,并且你理解它,那么如果你使用它就没问题。其他语言处理通用数据结构(映射/结构)和对象类型(具有属性)的概念,通常使用相同的语法,尽管事实上一个只是一个数据结构而另一个是一个富对象。 Objective-C中的程序员应该具有相同的能力来处理所有类型的编程,即使它不是您喜欢的编程。

答案 5 :(得分:6)

我将它用于属性,因为

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

更容易阅读
for ( Person *person in [group  people]){ ... }

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

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

[group.people addObject:another_person];

更具可读性
[[group people] addObject:another_person];

在这种情况下,重点应该是将对象添加到数组而不是链接两条消息。

答案 6 :(得分:5)

我大部分都是在Objective-C 2.0时代长大的,我更喜欢点符号。对我来说,它允许简化代码,而不是使用额外的括号,我可以使用一个点。

我也喜欢点语法,因为它让我真的感觉就像我正在访问对象的属性,而不仅仅是发送消息(当然dot-syntax确实翻译了进入消息发送,但为了出现,点感觉不同)。而不是用旧语法“调用getter”,我觉得我直接从对象中获得了一些有用的东西。

围绕此问题的一些争论涉及“但我们已经有点语法,而且它是structs!”。这是真的。但(又一次,这只是心理上的)它对我来说基本上是一样的。使用点语法访问对象的属性感觉与访问结构的成员相同,这或多或少是预期的效果(在我看来)。

****编辑:正如bbum指出的那样,你也可以使用点语法来调用对象上的任何方法(我没有意识到这一点)。所以我会说我对dot-syntax的看法只是为了处理对象的属性,而不是日常的消息发送**

答案 7 :(得分:3)

我更喜欢消息传递语法......但仅仅因为这是我学到的东西。考虑到我的很多课程以及Objective-C 1.0风格的课程,我不想混淆它们。我没有真正的理由除了“我已经习惯了”因为没有使用点语法...除此之外,这驱使我INSANE

[myInstance.methodThatReturnsAnObject sendAMessageToIt]

我不知道为什么,但它真的激怒了我,没有充分的理由。我只是觉得这样做

[[myInstance methodThatReturnsAnObject] sendAMessageToIt]

更具可读性。但对他自己来说呢!

答案 8 :(得分:3)

老实说,我认为这归结为一种风格问题。我个人反对点语法(特别是在发现你可以将它用于方法调用而不仅仅是读/写变量之后)。但是,如果您打算使用它,我强烈建议将其用于除访问和更改变量之外的任何其他内容。

答案 9 :(得分:3)

面向对象编程的一个主要优点是无法直接访问对象的内部状态。

在我看来,点语法是尝试使其外观和感觉,就好像直接访问状态一样。但事实上,它只是行为上的语法糖-foo和-setFoo:。我自己,我更愿意直言不讳。点语法有助于提高可读性,使代码更简洁,但它无助于理解,因为没有记住你真正调用-foo和-setFoo:可能会带来麻烦。

在我看来,合成访问器是一种尝试,可以轻松编写直接访问状态的对象。我的信念是,这鼓励了创建面向对象编程以避免的程序设计。

总的来说,我宁愿点语法和属性从未被引入过。我以前能够告诉人们ObjC是C的一些干净的扩展,使它更像Smalltalk,我不认为这是真的。

答案 10 :(得分:2)

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

答案 11 :(得分:2)

许多人似乎在混淆'属性'和'实例变量'。 我认为,属性的重点是可以修改对象而不必知道它的内部结构。大多数情况下,实例变量是属性的“实现”(反过来又是'接口'),但并非总是如此:有时属性不对应于ivar,而是计算返回值'在飞行中'。

这就是为什么我相信“点语法诱使你认为你正在访问变量以使其混乱”的想法是错误的。点或括号,你不应该对内部做出假设:它是一个属性,而不是一个ivar。

答案 12 :(得分:1)

使用点符号(无论何时)

在实例方法上返回一些值

请勿使用点符号

在init方法或Class方法上返回void的实例方法。

我个人最喜欢的例外

NSMutableArray * array = @[].mutableCopy;

答案 13 :(得分:1)

叫我懒,但如果我不得不键入一个'。'与两个[]每次获得相同的结果我更喜欢单一。我讨厌冗长的语言。口齿不清的()驱使我疯了。数学等优雅语言简洁有效,其他所有语言都不尽如人意。

答案 14 :(得分:1)

点符号尝试使消息看起来像对结构成员的访问,而不是它们。在某些情况下可能会正常工作。但很快就会有人提出这样的事情:

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

看起来很好。但事实并非如此。它与

相同
[myView frame].size.width = newWidth;

哪个不起作用。编译器接受第一个,但理所当然不接受第二个。即使它首先发出错误或警告,这也只是令人困惑。

答案 15 :(得分:1)

我想我可能会切换到消息而不是点符号,因为在我的脑海中 object.instanceVar 只是属于 object instanceVar ,对我而言,它看起来并不像方法调用那样,所以你的访问器中可能会发生一些事情以及你是否使用 instanceVar self.instanceVar 可能比简单的隐式与显式有更大的区别。只是我2¢。

答案 16 :(得分:0)

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

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

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

答案 17 :(得分:-2)

这是一个很好的问题,我看到了许多不同的答案。尽管许多人已经触及了这些话题,但我会尝试从不同的角度回答这个问题(有些人可能已经暗中做过):

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