点符号与消息符号的声明属性
我们现在有属性的“点”符号。 我已经看到各种各样的来回点符号与消息符号的优点。 为了保持答复的无污染,我不会在这个问题上作出任何回应。
你对点符号和消息符号的想法是什么?
请尽量保持对Objective-C的关注 – 我提出的一个偏见就是Objective-C是Objective-C,所以您的偏好就像Java或JavaScript是无效的。
有效的评论是关于技术问题(操作顺序,演员优先级,演出等),清晰度(结构与对象性质,亲和关系),简洁性等。
请注意,我是代码严格的质量和可读性的学校,在代码惯例和质量至关重要的大型项目上工作(编写了一千次的范例)。
不要使用点行为。 使用点来访问或设置属性,如东西,通常属性声明为属性。
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的新手来说,我build议不要使用任何东西,除了声明为@property的东西。 一旦你有了这种语言的感觉,做什么感觉是正确的。
例如,我发现以下非常自然:
k = anArray.count; for (NSView *v in myView.subviews) { ... };
您可以期望,铛静态分析仪将增加的能力,让您检查点只用于某些模式或不使用某些其他模式。
首先让我开始说,我开始编程Visual / Real Basic,然后转移到Java,所以我相当习惯点语法。 但是,当我最终移植到Objective-C并习惯括号,然后看到Objective-C 2.0及其点语法的介绍,我意识到我真的不喜欢它。 (对于其他语言来说很好,因为这就是他们如何滚动)。
在Objective-C中,我有三个带点语法的主要牛肉:
牛肉#1:这使得它不清楚为什么你可能会得到错误。 例如,如果我有这条线:
something.frame.origin.x = 42;
然后,我会得到一个编译器错误,因为something
是一个对象,你不能使用对象的结构作为expression式的左值。 但是,如果我有:
something.frame.origin.x = 42;
然后这个编译就好了,因为something
是一个结构本身有一个NSRect成员,我可以用它作为左值。
如果我采用这个代码,我将需要花一些时间来弄清楚什么是something
。 它是一个结构? 这是一个对象吗? 但是,当我们使用括号语法时,它更清晰:
[something setFrame:newFrame];
在这种情况下,如果something
是一个对象,则绝对不存在歧义。 含糊不清的是我的牛肉#1。
牛肉#2:在C中,点语法用于访问结构的成员,而不是调用方法。 程序员可以重写对象的setFoo:
和foo
方法,但仍然可以通过something.foo
访问它们。 在我看来,当我看到使用点语法的expression式时,我期待他们成为一个简单的分配到伊娃。 情况并非总是如此。 考虑一个调解一个数组和一个tableview的控制器对象。 如果我调用myController.contentArray = newArray;
,我希望它是用新的数组replace旧的数组。 但是,原始程序员可能已经重写了setContentArray:
不仅设置数组,而且还重新加载tableview。 从行,没有迹象表明这种行为。 如果我看到[myController setContentArray:newArray];
,那么我会认为“啊哈,一种方法,我需要去看这个方法的定义,只是为了确保我知道它在做什么”。
所以我认为我的牛肉#2的总结是你可以用自定义代码覆盖点语法的含义。
牛肉#3:我觉得它看起来不好。 作为Objective-C程序员,我完全习惯于括号化语法,所以要一起阅读,看看漂亮括号的行和行,然后突然用foo.name = newName; foo.size = newSize;
foo.name = newName; foo.size = newSize;
等等对我来说有点分心。 我意识到有些事情需要点语法(C结构),但这是我唯一使用它们的时间。
当然,如果你正在为自己编写代码,那么使用任何你喜欢的代码。 但是,如果你正在编写你正在计划开源的代码,或者你正在写一些你不希望永远保持的东西,那么我会强烈鼓励使用括号语法。 这当然只是我的意见。
最近的博客文章反对点语法: http ://weblog.bignerdranch.com/?p= 83
反对以上post: http ://eschatologist.net/blog/?p=226(原文赞成点语法: http ://eschatologist.net/blog/?p=160)
我是一个新的Cocoa / Objective-C开发人员,我认为这是:
即使我开始使用Obj-C 2.0,即使点符号更为熟悉(Java是我的第一语言),我仍然坚持使用消息传递符号。我的理由很简单:我仍然不明白为什么他们将点符号添加到语言中。 对我来说,这似乎是一个不必要的,“不纯”的加法。 虽然如果任何人都可以解释它对语言的好处,我很乐意听到。
然而,我认为这是一种风格的select,我认为只要它是一致的和可读的 ,就像任何其他的风格select一样,没有对错的方式(比如把你的大括号放在同一行方法头或下一行)。
Objective-C点符号是一个语法糖,被转换成正常的消息传递,所以在引擎盖下没有改变,在运行时没有任何区别。 点符号绝对不会比消息传递更快。
在这之后需要小序言这里是我看到的利弊:
点符号优点和缺点
-
利弊
- 可读性:点符号比嵌套括号更易于阅读传递
- 它简化了与属性和属性的交互:使用点符号表示属性和消息符号表示方法,可以在合成器级别实现状态和行为的分离
- 可以使用复合赋值运算符(1) 。
- 使用
@property
和点符号编译器为你做了很多工作,它可以在获取和设置属性时生成良好的内存pipe理代码; 这就是为什么点符号是由苹果官方指南build议的。
-
缺点
- 点符号只允许访问声明的
@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];
使用语言的风格,与语言本身一致,是最好的build议。 但是,这不是在OO系统中编写function代码的情况(反之亦然),点符号是Objective-C 2.0语法的一部分。
任何系统都可能被滥用。 所有基于C语言的预处理器的存在足以做出非常奇怪的事情; 只要看看混淆的C比赛,如果你需要看到究竟有多奇怪它可以得到。 这是否意味着预处理器自动坏了,你不应该使用它?
使用点语法来访问在界面中定义的属性,可能会被滥用。 在潜在的滥用的存在不一定是反对它的论据。
物业访问可能有副作用。 这与用于获取该属性的语法是正交的。 CoreData,委托,dynamic属性(first + last = full)都必须在下面做一些工作。 但是这会让“实例variables”和对象的“属性”混淆。 没有理由为什么一定要存储属性,特别是如果它们可以被计算(例如,一个string的长度)。 因此,无论您使用foo.fullName还是[foo fullName],仍然会进行dynamic评估。
最后,属性的行为(用作左值 )是由对象本身定义的,例如是否获取副本或是否保留副本。 这使得稍后改变行为更容易 – 在属性定义本身 – 而不是必须重新实现方法。 这增加了方法的灵活性,从而可能导致出现更less(实施)错误。 仍然有可能select错误的方法(即复制而不是保留),但这是一个架构而不是实现问题。
最终归结为“它看起来像一个结构”的问题。 这可能是迄今为止辩论的主要区别。 如果你有一个结构体,它的工作方式与拥有一个对象的方式不同。 但是这一直是事实。 你不能发送一个结构的消息,你需要知道它是基于堆栈还是基于reference / malloc。 已经有用法不同的心智模型([CGRect alloc] init]或struct CGRect?)。 他们在行为方面从未统一; 你需要知道你在每种情况下处理什么。 为对象添加属性variables不太可能会混淆任何知道数据types的程序员; 如果他们不这样做,他们会遇到更大的问题。
至于一致性; (Objective-)C本身是不一致的。 =用于赋值和相等,基于源代码中的词汇位置。 *用于指针和乘法。 布尔是字符,而不是字节(或其他整数值),尽pipe是和NO分别为1和0。 一致性或纯度不是语言devise的目的; 这是关于完成任务。
所以如果你不想使用它,不要使用它。 让它做一个不同的方式。 如果你想使用它,并且你理解它,那么使用它就可以了。 其他语言处理通用数据结构(地图/结构)和对象types(具有属性)的概念,尽pipe事实上只是一个数据结构而另一个是丰富的对象,但它们通常使用相同的语法。 Objective-C中的程序员应该具有相同的能力来处理所有types的编程,即使它不是您的首选。
我使用它的属性,因为
for ( Person *person in group.people){ ... }
比阅读起来要容易一点
for ( Person *person in [group people]){ ... }
在第二种情况下,可读性通过将大脑置于消息发送模式而被中断,而在第一种情况下,显然您正在访问组对象的people属性。
修改集合时,我也会使用它,例如:
[group.people addObject:another_person];
比可读性好一点
[[group people] addObject:another_person];
在这种情况下的重点应该是在向数组添加对象而不是链接两条消息的操作中。
我主要是在Objective-C 2.0时代提出的,我更喜欢点符号。 对我来说,它允许代码的简化,而不是有额外的括号,我可以使用点。
我也喜欢点语法,因为它使我真的觉得我正在访问对象的属性,而不是只是发送一条消息(当然,点语法实际上会转化为消息发送,但为了performance,点感觉不一样)。 而不是用旧的语法“调用getter”,它真的觉得我直接从对象中获得一些有用的东西。
围绕这个问题的一些争论是关于“但是我们已经有了点语法,这是为了structs
!”。 这是真的。 但是(再一次,这只是心理上的),它对我来说基本上是一样的。 使用点语法访问一个对象的属性感觉就像访问一个结构成员一样,这或多或less是预期的效果(在我看来)。
****编辑:如bbum指出的,你也可以使用点语法来调用对象的任何方法(我不知道这一点)。 所以我会说我对dot-syntax的看法只是处理一个对象的属性,而不是日常的消息发送**
我更喜欢消息传递的语法……但仅仅因为这是我学到的东西。 考虑到我的很多课程,Objective-C 1.0的风格,我不想混合它们。 除了“我以前习惯的”之外,我没有任何真正的理由不使用点语法……除此之外,这使我疯狂
[myInstance.methodThatReturnsAnObject sendAMessageToIt]
我不知道为什么,但是真的让我恼火,没有理由。 我只是觉得这样做
[[myInstance methodThatReturnsAnObject] sendAMessageToIt]
更具可读性。 但是对于他自己!
老实说,我认为这归结为一个风格问题。 我个人是反对点语法(特别是在发现你可以使用它的方法调用,而不是只读/写variables)。 但是,如果你打算使用它,我强烈build议不要使用它来访问和更改variables以外的任何东西。
面向对象编程的主要优点之一是不能直接访问对象的内部状态。
点语法在我看来似乎是试图让它看起来和感觉,就像直接访问状态一样。 但实际上,这仅仅是行为-foo和-setFoo上的语法糖。 我自己,我更喜欢用铁锹。 点语法有助于可读性达到代码更简洁的程度,但是它并不能帮助理解,因为没有记住你正在调用-foo和-setFoo:可能会造成麻烦。
对我来说,合成访问器似乎试图使写直接访问状态的对象变得容易。 我的看法是,这鼓励了正是为了避免而创build面向对象编程的程序devise。
总的来说,我宁愿点语法和属性从来没有被引入。 我曾经能够告诉人们ObjC是C的一些干净的扩展,使它更像Smalltalk,我不认为这是真的。
在我看来,点语法使得Objective-C更lessSmalltalk式。 它可以使代码看起来更简单,但增加了含糊性。 它是一个struct
, union
还是对象?
许多人似乎在将“属性”与“实例variables”混合在一起。 这些属性的重点是使我们能够修改对象,而不必知道它的内部。 实例variables在大多数情况下是属性的“实现”(反过来就是“接口”),但并不总是:有时一个属性不对应于一个ivar,而是计算一个返回值'在飞行中“。
这就是为什么我相信“点语法欺骗你认为你正在访问variables,所以这是混乱”的想法是错误的。 点或支架,你不应该做内部的假设:这是一个财产,而不是一个伊娃。
我想我可能会切换到消息传递,而不是点符号,因为在我的头object.instanceVar只是属于对象的 instanceVar ,对我来说,它不看所有像一个方法调用 ,这是,所以可能有事情要做在你的访问器上,以及你是否使用instanceVar或self.instanceVar可以有更多的差异比简单的隐式与显式。 只是我2¢。
点符号试图使消息看起来像访问一个结构的成员,他们不是。 在某些情况下可能工作正常。 但很快有人会想出这样的事情:
NSView *myView = ...; myView.frame.size.width = newWidth;
看起来很好 但是不是。 这是一样的
[myView frame].size.width = newWidth;
这不起作用。 编译器接受第一个,但是正确地不接受第二个。 即使它发出了第一个错误或警告,这只是混淆。
打电话给我懒,但如果我不得不input一个'。' 每次比较两个,以获得相同的结果,我宁愿单一。 我讨厌冗长的语言。 ()在lisp驱使我坚果。 math等优雅的语言简洁而有效,其他的都不尽人意。
使用点符号 (只要可以)
在实例方法返回一些值
不要使用点符号
在实例方法返回void,在init方法或Class方法。
而我个人最喜欢的例外
NSMutableArray * array = @[].mutableCopy;
我个人在代码中完全不使用点符号。 我只在需要时才将它用于CoreData KVC绑定expression式。
没有在代码中使用它们的原因是点符号隐藏了setter语义。 无论setter语义如何(assign / retain / copy),以点表示法设置属性总是看起来像赋值。 使用消息标记可以看到,接收对象可以控制setter中发生的事情,并强调了这些效果需要考虑的事实。
我仍然在考虑在检索KVC兼容或声明属性的值时是否可能使用点符号,因为它承认它更紧凑,更易读,并且没有隐含的语义。 为了保持一致性,我现在坚持使用消息符号。
好的,Objective-C中的点符号的确很奇怪。 但是如果没有它,我仍然不能做到:
int width = self.frame.size.width;
工作正常,但:
int height = [[[self frame] size] height];
给我“不能转换为指针types”。 不过,我真的希望保持我的代码与消息符号一致。
这是一个很好的问题,我看到很多不同的答案。 虽然很多人已经谈到了这些话题,但我会试着从不同的angular度来回答这个问题(有些人可能已经暗示):
如果我们使用“点”符号,则方法的目标分辨率是在编译时完成的。 如果我们使用消息传递,则目标的parsing被推迟到运行时执行。 如果在编译时parsing目标,执行速度会更快,因为在运行时parsing目标包含一些开销。 (不是时差会很重要)。 由于我们已经在对象的接口中定义了属性,所以对于属性的运行时目标的parsing是没有意义的,因此点符号就是我们应该用来访问属性的符号。