I'm diving into iOS programming and I'm having difficulty getting my head around the idea of Dot Notation and Method Notation.
As far as I understand it, Dot Notation can be used to invoke setters/getters on properties and is much more cleaner to write/read. Method Notation is used to send messages to objects to manipulate them etc.
Could someone give me a simple explanation as to why the following two statements are essentially different and one will compile but the other will instead fail due to a syntax error.
- (IBAction)digitPressed:(UIButton *)sender
{
NSString *digit = [sender currentTitle];
self.display.text = [self.display.text stringByAppendingFormat:digit];
self.display.text = self.display.text.stringByAppendingFormat:digit;
}
Thanks.
You're entering into Objective-C development at an interesting time where old syntax is being used with new syntax. Dot syntax is syntactic sugar and there are some cases where you can use it but you should not.
The following is invalid syntax. Anything where you'd use a colon (besides setters or getters), you won't use dot notation.
self.display.text = self.display.text.stringByAppendingFormat:digit;
Also, you would use stringByAppendingString, not stringByAppendingFormat
You use dot notation for accessing variables, not for calling actions that will have effects.
Correct:
self.foo.attributeOfMyClass
Incorrect:
self.foo.downloadSomethingFromAWebsite
Ensuring you always use dot notation for accessing property values and you always use bracket notation (even when you don't have to) for calling action methods, your code will be much clearer upon a glance.
Dot notation is just shorthand for a specific kind of method--namely, accessors. You may use it in the following cases:
When setting a property: foo.bar = 3; is equivalent to [foo setBar:3];.
When requesting a property: in any case except the one above, foo.bar is equivalent to [foo bar].
Dot notation is only shorthand--there is nothing magic about its relationship to properties. You could theoretically use dot notation to send any message that takes no arguments (foo.doSomething), but this would be very very bad style, as dot notation is intended for properties. Also note that if dot notation vs. square brackets is confusing you while you're learning, it's a perfectly valid choice to avoid dot notation altogether. It's just one shortcut you may use for accessors, if you like.
Actually, your second statement is not correct. Objective C way to invoke methods (messages) is using the [instance message] syntax.
As you said, the dot notation is just to call getters and setters on class properties, but not messages, that's why your second statement is not correct. The two lines you may wanted to compare are:
self.display.text = [self.display.text stringByAppendingFormat:digit];
[[self display] setText:[[[self display] text] stringByAppendingFormat:digit]];
Note that the message stringByAppendingFormat has to be called the normal way.
The dot notation is just to write faster and not so many brackets, but it will execute exactly the same instructions once compiled.
Another reason for using selector notation rather than dot notation is due to the dynamic language features in Objective C. As an example, consider the following:
NSString *s = #"Hello World!";
NSLog(#"Length is %d", s.length);
This works as we would expect. However, objects in Objective C may be passed around with type id. Consider the following:
id s = #"Hello World!";
NSLog(#"Length is %d", s.length);
This won't compile, as id doesn't have a property called length. The following will work, however:
id s = #"Hello World!";
NSLog(#"Length is %d", [s length]);
The reason this works is that Objective C knows about NSString, and so knows that there is some object type that responds to the selector length. Of course, if you try the following:
id s = [[UIView alloc] init];
NSLog(#"Length is %d", [s length]);
Your code will compile correctly, but a runtime exception will occur (unrecognized selector sent to instance) as UIView does not have a length selector.
Let's say we have the class Class with the variable variableOne we are going to use both notations.
Dot notation is the purest way to access a variable. It is also the way that bracket notation is most likely doing it behind the scenes. By typing Class.variableOne... variableOne is a part of Class and the "." after the class tells the compiler that it would like to access a part of the class--either a variable or a method.
Bracket notation is uses a method to access the variable. Let's say...
-(int) setVariable:x {
self.variableOne = x;
}
-(int) showVariable {
return self.variableOne
}
So when you're using bracket notation to set the variable [variableOne setVariable:5] or displaying the variable [variableOne showVariable] it calls the appropriate method.
This is a very simple way to think of the difference, I realize another answer has already been accepted but perhaps this answer will explain it for someone who didn't understand another answer.
When your code gets compiled, clang actually first takes all of your dot notation and turns it into method/bracket notation, so self.display and [self display] are exactly the same. Dot notation is actually fairly new as of Objective-C 2.0. It's simply for convenience.
Dot notation can only be used for properties, because doing something like you tried to do (which will not compile) gets cumbersome:
self.display.text.stringByAppendingFormat:digit;
It also wouldn't work for methods that take multiple arguments since you'd need to put spaces between arguments and suddenly the line of code would look awkward and hard to read.
Related
I'm very new to Objective-C and programming in general and I'm having some difficulty solving a strange error I'm getting in my code. I've rechecked my code line-by-line but no matter what I do I get an "Expected Identifier" error on this one line.
NSString *text = [NSString stringWithFormat:#"Your total is $%.2f", [self.cartTotal]];
I've retyped the line several times to make sure that I wasn't missing any typos, but a little red arrow is pointing to the first closing bracket.
Take [self.cartTotal] out of the brackets. They're unnecessary here.
Should be:
NSString *text = [NSString stringWithFormat:#"Your total is $%.2f", self.cartTotal];
To help understand the error (assuming you're coming from a language like Java or C++), what you've written is the equivalent to writing this in say Java:
this.cartTotal.
Notice the hanging dot at the end? That's what you've done here basically. In Java, that dot suggests you're calling a method on whatever object cartTotal is, or access a public variable on that object. I'm not sure what a Java or C++ error message would say here, but this is the equivalent scenario.
Given #GregParker's excellent comment...
You created cartTotal by way of a #property.
#property double cartTotal; // or something like this
This creates three things:
A setter
A getter
An instance variable
The setter is accessed in two ways:
[self setCartTotal:value];
Or:
self.cartTotal = value;
These both do the same thing.
The getter is likewise accessed in two ways:
[self cartTotal];
Or:
self.cartTotal;
For example,
CABasicAnimation *rotate = [CABasicAnimation animationWithKeyPath:#"transform.rotation"];
[rotate setToValue:#(M_PI)];
[rotate setDuration:0.1f];
[[aView layer] addAnimation:rotate forKey:#"myRotationAnimation"];
where M_PI is defined as a macro in math.h,
#define M_PI 3.14159265358979323846264338327950288 /* pi */
It's a pointer to an NSNumber object. It's called a boxed literal, because the mental picture is of putting a primitive value of expression inside into a "box", that is, an object.
See official documentation if in doubt. Note that pointer can be to a "real" NSNumber object or it can (theoretically, don't know whether this will work in practice) be a tagged pointer (see, e.g., my question).
Note that you can also do things like #"string" and #5, which will create constants in compile time. But you need parentheses to use something which is not a literal, e.g. #(2 + 3). Parentheses form can be used for any expression, even those that compiler cannot compute at compile-time (although if it can, it will just put an expression result into code).
NeXT and Apple Obj-C runtimes have long included a short-form way to create new strings, using the literal syntax #"a new string". Using this format saves the programmer from having to use the longer initWithString or similar methods when doing certain operations.
When using Apple LLVM compiler 4.0 or later, arrays, dictionaries, and numbers (NSArray, NSDictionary, NSNumber classes) can also be created using literal syntax instead of methods. Literal syntax uses the # symbol combined with [], {}, (), to create the classes mentioned above, respectively.
So, basically it's not only for id or NSNumber object!
thanks to wiki.
It's Shorthand writing
In Objective-C, any character, numeric or boolean literal prefixed with the '#' character will evaluate to a pointer to an NSNumber object (In this case), initialized with that value. C’s type suffixes may be used to control the size of numeric literals.
'#' is used a lot in the objective-C world. It is mostly used to avoid taking english words and making them reserved (for example, you can't have a variable called float in C/Objective-C because this is a reserved word).
Use this link To have detailed knowledge of '#' symbol.
In Modern Objective C, '#' symbol is used extensively.
What You can do with it:
calculate an expression: #(<Expression>)
wrap any value like int,bool,float,char in same way
Reasons to use:
Easy to write, Less code required
Less chances of mistakes. Compare [NSNumber numberWithInt:3] with #3.
Get rid of typecasting issues in simple cases.
It represent id Object
that you can use any expression in it or return any object.
Syntax : #(<#expression#>) it will return id object.
So in your case it will returning NSNumber object to setToValue method.
While in the process of debugging code written by a co-worker, I stumbled across the following that has me mystified:
NSMutableArray *array = [NSMutableArray array];
NSUInteger arrayCount = array.count;
Why does this work? It also works for NSDictionary and other types, but nowhere in the documentation nor Cocoa headers can those #property definitions be found.
Googling for "NSArray property" doesn't yield many useful results, so I'm reaching out to SO for what will surely be a very embarrassing question.
It works because dot syntax has nothing to do with properties. It is simply syntactic sugar (though I don't like it, so perhaps it's "syntactic salt").
When you use dot syntax as the rvalue to an expression (or the expression to the right of the equal sign), it simple turns:
bar = myObject.thing;
Into
bar = [myObject thing];
When the dot is to the left of the equal sign (as an lvalue), it turns it into the setter. So:
myObject.thing = 42;
Becomes
[myObject setThing:42];
So yes, you can do things like myObject.retain. But you should never ever do that. You should only ever use dot syntax as accessors to declared properties (ie, things that have been explicitly declared via #property). <insert remark about how you should never use dot syntax at all.>
For more information, checkout out the documentation on dot syntax (specifically the "incorrect use" section).
the dot syntax is actually just an alternative for accessing methods that either take no parameter and return a value like array.count. It is bad form to actually access the methods in that way.
It can also be used for things like [object setValue:(id)something] and access it by doing object.setValue = something;
i am viewing this video on objective c. the guy show a method which takes multiple arguments and it looks like this
- (void) setTo: (int) n over: (int) d
{ .... }
to use it he shows:
[myFraction setTo: 100 over:200];
how would that bracket notation look in dot noation? andi dont understand what that over
means, would anyone know? thnx
The dot notation is a shorthand notation for property access only. The compiler translates it to the appropriate setter/getter method call. It is just syntactic sugar.
So given this property access using dot notation:
myFraction.numerator=100;
The compiler replaces it with the following equivalent code:
[myFraction setNumerator:100]
Now it should be clear why you cannot use dot notation for sending a normal message to an object. I can't even think of a way how that should even look like.
There is a lot of discussion concerning dot vs. bracket notation going on. One of the arguments against dot notation is the confusion it generates especially for beginners. Other languages do of course use methods for property accessors too, however they hide this fact more consistently than Objective-C.
You cannot pass multiple arguments with dot notations. A setter usable by dot-notation must have the prototype
-(void)setXxxx:(type)value;
However, you can create an auxiliary struct to group all arguments into one:
struct Fraction { int n, d; };
struct Fraction MakeFraction(int n, int d) {
struct Fraction r;
r.n = n;
r.d = d;
return r;
}
...
-(void)setValue:(struct Fraction)f { ... }
...
myFraction.value = MakeFraction(100, 200);
(and a "over" b means a / b.)
From the looks of it, this method is setting two instance variables/properties of the object the numerator (n) and the denominator (d). You cannot do this using dot notation unless you break it into two calls:
myFraction.numerator=100;
myFraction.denominator=200;
Note that dot notation is only for accessing instance variables/properties and not an alternative to message sending.
In Objective-C, we can name methods with arguments in the middle. So when he writes [myFraction setTo:100 over:200];, the over could mean... well, whatever he wants. It's part of the method name he chose. In this case, he was probably trying to make the method sound like English. ("Set this fraction to 100 over 200." We read fractions as "numerator over denominator" often in normal speech.)
Some methods, called "accessors", we write very frequently: these are methods of the form - (int)variable (called "getters"), and - (void)setVariable:(int)newValue (called "setters"). My examples here would assumedly return, or change, respectively, an instance variable called variable. Here's what the method implementations might look like:
- (int)variable
{
return variable;
}
- (void)setVariable:(int)newValue
{
variable = newValue;
}
It's common to have accessors like this for almost every instance variable your class has. At some point, someone got tired of writing [myInstance setVariable:20]; and such, and decided they'd rather it look like many other languages out there, myInstance.variable = 20;.
Therefore, Objective-C 2.0 added dot notation, which allows you to write...
myInstance.variable, which is exactly equivalent to [myInstance variable] in most circumstances (and does NOT access the instance variable variable directly!), and...
the special case myInstance.variable = 20;, which is exactly equivalent to [myInstance setVariable:20];. Again, note that this does not access variable directly, it sends a message to myInstance. So if we'd written some other code in setVariable, it would still be accessed if we used dot notation.
Dot notation is designed to be used for accessors. You could also theoretically use it for any method that returns a value and takes no arguments (myArray.count, for example). Using it for anything else (myInstance.doSomeAction) is extremely poor style. Don't do it. Therefore, as I'm sure you can guess by now, [myFraction setTo:100 over:200] has no dot notation equivalent, as it takes 2 arguments, and isn't an accessor.
[myFraction numerator]
Could be written as
myFraction.numerator
but you can also assign values such as
instance.property = value
But you cannot pass multiple arguments in dot notation.
This code...
NSString * s = [[NSString alloc] initWithString:#"Hello, World"];
s = s.lowercaseString;
NSLog(#"%#", s);
...allows the use of dot notation but is strongly typed.
This code...
id s = [[NSString alloc] initWithString:#"Hello, World"];
s = [s lowercaseString];
NSLog(#"%#", s);
... is weakly typed and requires use of square brackets.
Other than that, is there any advantage of using one over the other?
If you're creating an NSString, then you might as well declare it as an NSString, and let the compiler help you.
The point of using id is to prevent strong coupling, and to use objects whose types are not known until a later time. e.g IBAction methods include the sender as a parameter as an id, because the exact type of the object isn't known.
Edited to add:
You may be new to the language, so I'll mention a couple of things
Firstly, where you have #"Hello, World", you already have an NSString, just one that is static. So you don't need to go through initWithString to create it. Just write:
NSString *s = #"Hello, World";
And, because you didn't alloc it, you don't have to worry about releasing it.
Secondly s.lowerCaseString. As Stephen has already answered, this is considered to be bad style. When you change a string to lower case, you aren't getting a property of the the string, you are causing an operation to be done on the string, in which case, you really should use bracket syntax.
Yes. The compiler warns you if you try to put a NSString into a method that expects a NSNumber.
It's more likely that the compiler finds your mistakes.
Arguably the former code is incorrect. You should only really use the dot notation to get/set properties, and lowercaseString is a method.
Otherwise, as you suggest, the only real difference is type safety. If you had a typo, say you put [a loercaseString], the compiler wouldn't shout at you.
There are certainly cases where you'd use id but your example is not one of them