转自:https://www.bignerdranch.com/blog/dot-notation-syntax/
When I teach, I always make sure to mention the dot-notation addition to Objective-C 2.0. Then, I make sure to tell the students never to use it ever, ever, ever again. But why? Why this seemingly irrational hatred of dot-notation? Is this a style choice and us “bracketeers” are being hard-headed? The answer is no, we are not being hard-headed, we are keeping our code consistent and maintaining readability.
### The Intent of Code
The naming conventions used in Cocoa and Cocoa Touch are clear and straightforward. When we look at well written Mac or iPhone code, we can tell exactly what is going on by glancing at it. That’s the power that Objective-C gives us. If I want an object to take a drink of water while doing a cartwheel, I send it the message: `
[obj takeDrinkOfLiquid:water whileDoingCartwheel:YES];
`
We know exactly what that means. There is no room for interpretation. Likewise, we know exactly what this line of code does: `
a = b + 5;
` This adds b and the value 5 together and assigns the result to the variable a. We get these operators, = and +, from the C programming language. We have a lot more operators in C, like ***, **/, -, % and &. And we know what all of those operators mean. When we see them, we say stuff like, “That’s a division!” or “That’s a subtraction!” Except we don’t say that. We don’t even think about that. We instantly know.
Another operator that is commonly used in C is the . operator. The dot operator accesses a member of a structure. It goes to an address in memory (the address of the structure object) plus an offset. That’s all it does. We instantly know what it means.
Sometimes, an operator may have another meaning depending on the context. For example, the*** operator could be dereferencing a pointer or it could be doing a multiplication. However, the context this operator is being used in allows us to easily discern which operation is occuring. The dereferencing *** is a unary operator and the multiplication ***** is binary operator. When we look at code, we know which one is being used. `
int a = *ptr; // Definitely a dereference!
int c = a * b; // Definitely a multiplication!
int c = a * (*b); // Definitely both!
`
In Objective-C, the square brackets ([]) were added for message sending. While the square brackets had previously only been used for indexing an array, the intent of the brackets can be easily determined by the context. `
【yasi】在Objc 2.0之前,没有点语法糖,下面代码中的 [] 使得 send message 和 indexing 没有歧义
[object message]; // Definitely a message send!
int a = variable[index]; // Definitely indexing!
`
With that, we can say that we definitely know what the operators in Objective-C do with a quick look.
### Then comes Objective-C 2.0…
With Objective-C 2.0, we get dot-notation. Many programmers new to Objective-C like dot-notation, it reminds them of other languages that they are more proficient in. Except for dot notation doesn’t do the same thing in Objective-C as it does in other languages.
Dot-notation in Objective-C invokes an instance method. Code in a method definition is executed when this dot is used. This code could be simple and it could just return a value. That doesn’t cause much of a problem. However, what if that method is a lot beefier: `
- (int)value
{
NSData *valueWrapper = [NSURLConnection sendSynchronousRequest:...];
if(valueWrapper)
{
const int *v = [valueWrapper bytes];
return *v;
}
return -1;
}
That method could go wrong in a number of ways. When we see the invocation of that method with dot-notation, all we see is:
int x = foo.value;
` What does that mean? Are we getting the value field out of the structure object foo? Are we executing a simple method that returns a value? Or, in this case, are we creating a network connection, pulling a value from a web server, turning that data in to an integer and then returning it?
It is ambiguous. With dot-notation, we don’t know exactly what this code means at first glance. When we see this code: `
int x = [foo value];
` Our first glance tells us we are definitely sending a message. That clues us in that more work is being done, not just a simple memory offset and an assignment.
What is more confusing, especially to Objective-C newcomers, is invoking a setter method with dot-notation. `
【yasi】从Objc 2.0开始,下面的代码会给人带来歧义。按照C的语法,它是给foo的struct的object属性赋值。按照 Joe 的说法,在Objc中,没这么简单,下面的用法是不建议使用的,因为它会被编译器理解成 [foo object] = otherObject
foo.object = otherObject;
`
In C or C++, this is a simple assignment. In Objective-C, this could easily be creating a copy ofotherObject or retaining otherObject. It is not immediately apparent from that line of code. The difficulty of understanding reference counting as a beginner gets amplified by code like this. Our code takes longer to read. We have to dig around to determine what is actually happening in this line of code.
Same context, same operator, different operation. We don’t know what this operator does anymore.
### Return Values
Here is another example: `
【yasi】下面的代码,在C中是简明易懂的,就是给struct的属性赋值。按照 Joe 的说法,点语法糖的返回值是lvalue,是不能被赋值的;somePerson.age 会被编译器理解成 [somePerson age] 的方法调用,默认返回一个lvalue 的返回值,该返回值不能被赋值。然而,XCode 6.1.1 和 OS X Yosemite (10.10) 的情况下没有出现 Joe 提到的编译错误。
someView.frame.size.width = 30;
`
【yasi】[[[someView frame] size] width] = 30 或者 [somePerson age] = 30 是会报错的:Expression is not assignable 或 Assigning to 'readonly' result of an Objective-C message not allowed。综上,看上去,点语法糖在 XCode 6.1.1 和 OS X Yosemite (10.10) 的情况下是能正常使用的。但是,为了确保代码的可读性和一致性,不建议使用点语法糖。同时,无论如何,像 [somePerson age] = 30 的用法都是错误的。
Very straightforward, we’re setting the width of a view’s frame to 30 pixels.
Actually, no. We are not. We’re generating a compiler error. The value returned by a dot-notation invocation is not an lvalue. We can’t assign it anything. However, if someView is a structure, that line of code will work as intended. `
someView.frame.size.width = 30; // This is valid code!
`
We lose consistency in our code using the dot operator. An operator in the same context, one is valid code, one is not. (It’s also a good thing that first line generates a compiler error, otherwise, we’d only be changing the copy of someView’s frame, not the instance variable of someView.)
Now, that is confusing.
### But I’m used to C#, C++, Java. Dot-notation looks like I’m at home!
You aren’t at home. You’re working with another language.
If one language solved all problems, everyone would use that language. Each language and API is a tool and it has an intended use. Using dot-notation in Objective-C would be akin to pounding nails in with a screwdriver. Sure, it works most of the time, but it isn’t the best use of a screwdriver or the best way to hammer nails. Eventually, you might smash your own hand.
Users of dot-notation are typically new to Objective-C. This is most likely the intention of dot-notation; a more familiar syntax for programmers coming from other languages. However, you would be better off familiarizing yourself with Objective-C then pretending it is another language. You will spend less time confused and more time solving a bigger problem.
### Apple uses it in their sample code, though!
That’s right, they do. Now, despite what the kool-aid is making you think, Apple does occasionally get something wrong. Their sample code has always been hastily crafted to get developers to use their platform. It is not always the best example of how to use a language.
It is my belief, after teaching roughly 300 students Objective-C, that dot-notation is confusing. It hinders the main goal of software development: writing maintainable, effective, efficient, easy to read and bug-free code.
In the end, there is wrong way and a right way to write Objective-C code. I will not say that using dot-notation is the wrong way. It is an acceptable way to write Objective-C code. I will, however, say there is a better way to write your code. The better way does not include dot-notation.