你对使用点表示法与使用消息表示法来访问属性有什么想法?
请尽量集中讨论Objective-C - 我的一个偏见是Objective-C就是Objective-C,所以你认为它应该像Java或JavaScript那样的偏好是无效的。
有效的评论与技术问题(操作顺序、转换优先级、性能等)、清晰度(结构与对象性质,利弊双方!)、简洁性等有关。
请注意,我是严格追求代码质量和可读性的学派,在这些巨大的项目中工作过,代码规范和质量至关重要(一次编写,千万次阅读的范例)。
不要使用点来表示行为(behavior)。使用点来访问或设置像“stuff”这样的属性,通常是声明为属性的属性。
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静态分析器将增强其功能,使您能够检查点是否仅用于某些模式或不用于其他某些模式。
.uppercaseString
之类的方法就不会感到模糊了。也许我还缺少一些东西,需要当前点表示法的实现。 - user155959@property
,但这将要求API的使用者学习另一个布尔信息维度,并且API的设计者很可能会在应该和不应该成为@property
的参数上陷入争论。请注意,Xcode更喜欢——更加重视——在完成代码时隐含的@property
方法。这是鼓励的,但并非强制性的。 - bbummyObj.prop
还是 [myObj prop]
进行编码? - rodamn首先,我想说我以前使用过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
是一个对象还是其他,就没有任何歧义。引入歧义是我的第一个抱怨。
争议2:在C语言中,点语法用于访问结构体成员,而非调用方法。程序员可以重写对象的setFoo:
和foo
方法,但仍然可以通过something.foo
访问它们。当我看到使用点语法的表达式时,我期望它们是简单地分配给ivar,但这并不总是正确的。考虑一个控制器对象,它协调数组和表视图。如果我调用myController.contentArray = newArray;
,我希望它将旧数组替换为新数组。但是,原始程序员可能已经覆盖了setContentArray:
,不仅设置数组,还重新加载表视图。从代码行中,无法得知该行为。如果我看到[myController setContentArray:newArray];
,那么我会想:“啊哈,一个方法。我需要去查看此方法的定义,以确保我知道它正在做什么。”
所以我认为我对争议2的总结是:您可以使用自定义代码来覆盖点语法的含义。
争议3:我认为它看起来很糟糕。作为一个Objective-C程序员,我完全习惯括号语法,因此阅读美丽的括号行和行的代码,然后突然被foo.name = newName; foo.size = newSize;
等打断有点分散我的注意力。我意识到有些东西需要使用点语法(C结构体),但那是我使用它们的唯一时间。
当然,如果您正在为自己编写代码,则可以使用任何您感到舒适的内容。但是,如果您正在编写计划开源的代码,或者您正在编写不希望永远维护的代码,则强烈建议使用括号语法。当然,这只是我的意见。
反对点语法的博客文章:https://bignerdranch.com/blog/dot-notation-syntax/
对上述文章的反驳:http://eschatologist.net/blog/?p=226(支持点语法的原始文章:http://eschatologist.net/blog/?p=160)
something
是一个对象,但我遇到过几个地方,原作者创建了结构体(为了速度、更低的内存使用等),我不得不花费一些时间来弄清楚为什么代码无法编译。 - Dave DeLong我是一名新的Cocoa/Objective-C开发者,我的看法是:
我坚持使用消息传递符号,尽管我从Obj-C 2.0开始学习,即使点符号更加熟悉(Java是我的第一种语言)。我这么做的原因很简单:我仍然不完全明白为什么要将点符号添加到该语言中。对我来说,它似乎是一个不必要、"不纯"的添加。但是如果有人能解释它如何有益于该语言,我很乐意听取。
然而,我认为这是一种风格选择,我认为没有对错之分,只要保持一致和可读性,就像任何其他风格选择一样(比如把大括号放在方法头的同一行或下一行)。
Objective-C点表示法是一种语法糖,被翻译为普通的消息传递,在底层不会有任何变化,对运行时也没有影响。点表示法绝对不比消息传递更快。
经过这个必要的开场白,以下是我看到的优缺点:
优点
@property
和点表示法,编译器可以为你生成良好的内存管理代码当获取和设置属性时;这就是为什么点表示法被Apple自己的官方指南建议使用的原因。缺点
@property
。(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];
属性访问可能具有副作用。这与获取该属性使用的语法是正交的。CoreData、委托、动态属性(first+last=full)都必须在底层执行一些工作。但是这将会混淆“实例变量”和对象的“属性”。特别地,属性不一定需要被存储为原样,特别是如果它们可以被计算(例如字符串的长度)。因此,无论你使用foo.fullName还是[foo fullName],仍然会进行动态评估。
最后,属性的行为(当作为一个lvalue使用时)由对象本身定义,比如是否复制或保留。这使得更改行为变得更容易 - 在属性定义本身中 - 而不必重新实现方法。这增加了方法的灵活性,减少了发生错误的可能性。仍然有选择错误方法的可能性(即复制而不是保留),但这是一个架构问题而不是实现问题。
最终,归结为“它看起来像结构体吗”的问题。这可能是迄今为止辩论中的主要区别;如果你有一个结构体,它的工作方式与如果你有一个对象不同。但这一直是真的;你不能给结构体发送消息,并且你需要知道它是基于堆栈还是基于引用/分配的内存。已经存在在使用上存在差异的心理模型([[CGRect alloc] init]或struct CGRect?)。它们从行为上来说从未统一过;你需要在每种情况下知道你正在处理什么。为对象添加属性表示极不可能混淆任何知道他们数据类型的程序员;如果他们不知道,那么问题更大。至于一致性;(Objective-C)C本身是不一致的。=同时用于赋值和相等,基于源代码中的词汇位置。*用于指针和乘法。BOOL是char,而不是字节(或其他整数值),尽管YES和NO分别是1和0。一致性或纯洁性并不是这门语言的设计目标;它是关于完成任务。
所以如果你不想使用它,就不要使用它。用另一种方式完成任务。如果你想使用它,并且理解它,那么使用它是可以的。其他语言处理通用数据结构(映射/结构)和对象类型(具有属性),通常使用相同的语法,尽管其中一个仅仅是数据结构,而另一个则是一个丰富的对象。Objective-C程序员应该有能力处理所有编程风格,即使这不是你首选的编程风格。我使用它来表示属性,因为
for ( Person *person in group.people){ ... }
for ( Person *person in [group people]){ ... }
[group.people addObject:another_person];
,这个更易读。
[[group people] addObject:another_person];
我更喜欢消息语法...但只是因为这是我学习的方式。考虑到我的很多课程和其他内容都是以Objective-C 1.0风格为主,我不想混合使用。除了“我习惯了”之外,我没有真正的理由不使用点语法...除了这个问题,这让我疯狂。
[myInstance.methodThatReturnsAnObject sendAMessageToIt]
[[myInstance methodThatReturnsAnObject] sendAMessageToIt]
更可读。但每个人都有自己的喜好!
[self.title lowercaseString]
或其他类似情况。但我可以理解为什么在风格上混合使用语法会让人感到困扰。我之所以这样做是为了清楚地区分什么是属性,什么是返回对象的方法(我知道属性本质上就是这样的,但你应该明白我的意思)。 - jbrennan