converting dot syntax to bracket syntax on a struct - objective-c

I have a property of CGSize:
#property (nonatomic) CGSize descriptionSize;
'
#synthesize descriptionSize = _descriptionSize;
I can access the height through the dot syntax:
self.descriptionSize.height = 35;
but how does this work with the bracket syntax?
[self setDescriptionSize:???];
Looked stupid simple to me, but I can't get the clue. Thanks in advance!

This is one of the pitfalls of dot notation for properties: Those two dots in self.descriptionSize.height look the same but mean very different things. The first is a property accessor which maps to a "get descriptionSize" method, but the second is an old-school struct reference. The first dot returns a CGSize scalar, NOT a pointer to the size value in the object. When the second dot sets the height in that returned CGSize, it's setting a value on the stack instead of changing the value in the object. This is how you have to do it:
CGSize size = self.descriptionSize;
size.height = 35;
self.descriptionSize = size;
…or the equivalent without properties dot notation:
CGSize size = [self descriptionSize];
size.height = 35; // we still use the dot here: size is a struct not an object
[self setDescriptionSize:size];

The implementation of descriptionSize will return a copy of the CGSize struct, so you can't work directly with that and hope it will work. What you need to do is get the whole of the CGSize struct, modify it, and then pass it back in:
CGSize size = [self descriptionSize];
size.height = 35;
[self setDescriptionSize:size];
However given you are working on a property of self and the property isn't an object, which requires memory management, the most efficient way of modifying the size is:
_descriptionSize.height = 35;
However you'd use the former getter/setter approach if:
The object was not self.
You had manually written the setter method to do something as a side-effect of changing the size (for example invalidating bits of the view in order to automatically update the view).

Dot syntax can mean two different things: Either a struct reference (CGSize is a C struct), or an objective-C message send.
Theoretically, if you have a method like - (void)doSomething;, you could call it like this: myObject.doSomething; //bad style. Don't do this. Dot syntax is not meant for calling methods that actually do stuff, other than getting or setting values (although nothing in the language or the IDE is going to stop you).
Synthesizing properties creates accessor methods: - (myType)myProperty and - (void)setMyProperty:(myType)newValue. Here, dot syntax lets you access the getter in the ordinary way (because the getter is an ordinary Objective-C method), and has a special case for the setter: myObject.myProperty = newValue gets translated to [myObject setMyProperty:newValue].
This means you can switch between dot syntax and Objective-C style message sending syntax for properties (and technically for all other parameter-less Objective-C method sends), but you must use dot syntax to access struct members. Structs are not objects, and they know now methods.

Related

What is the function of "(ClassName *)"

I have seen code statements that use '(ClassName *)' to reference certain objects, like in UITableViewCell *myCell = (UITableViewCell*)[self.view viewWithTag:1];.
I have no idea what this means or how it works and I would like to increase my understanding of this concept.
I have also seen that the same code is also used in method declaration and would like to understand if this uses the same concept and if not, how is it different, e.g.
-(IBAction)myAction:(id)sender;
That serves as a typecast. It converts the type of the pointer to the type within the parentheses. In this case, it is converting a UIView instance (the result of `viewWithTag:) to an instance of UITableViewCell.
In ObjC, an object to object typecast does not result in a type conversion. That is to say - there is no new instance created. Additionally, typecasting an object performs no dynamic type checking when performing a dynamic downcast (unlike dynamic_cast in C++ or typecasting in Java, where an exception may be thrown).
Because -viewWithTag: returns a UIView (or NSView on OS X), a typecast is used to tell the compiler "It's OK - I know this type returned is a UITableViewCell instance". Using the typecast allows you to downcast from UIView to its subclass UITableViewCell in the assignment expression to the variable, which allows you to use the object as a UITableViewCell with the compiler matching the message or variable with the type. Without the typecast, you would logically be using it as or assigning it to a UIView (or one of its superclasses), and the compiler would complain if you tried to use methods implemented by subclasses of the instance. For example - you could not successfully use the variable to access the UITableViewCell.accessoryView property without either a typecast, type erasure, or a compiler warning or error. The typecast is the least evil in this case.
Now in the case of - (IBAction)myAction:(id)sender;, id is an untyped ObjC object. It has a special distinction in that it requires no typecast. For example:
- (IBAction)myAction:(id)sender
{
NSString * currentTitle = nil;
currentTitle = sender.currentTitle; // << May be ambiguous to the compiler because `id` is not fully typed
UIButton * button = sender; // << OK assign id to variable of arbitrary ObjC object type
currentTitle = button.currentTitle; // << OK
UIButton * castButton = (UIButton*)sender; // << although unnecessary, some people use this form.
currentTitle = castButton.currentTitle; // << OK
...
NSObject * object = button; // << OK. upcast from button to object. compiler knows it is an NSObject without typecasting.
Personally, I just wrap it all into the parameter -- which is fine for ObjC objects in method declarations as long as you know the type of the parameter which is being passed:
- (IBAction)myAction:(UIButton *)pButton
{
NSString * currentTitle = pButton.currentTitle; // << OK
...
Is just a typecast necessary to suppress the compiler warning.
In other words its saying to the compiler [self.view viewWithTag:1] is an UITableViewCell. Without that cast the compiler would complain that UIView is not a UITableViewCell.

Correct way of setting a BOOL property

I have a BOOL property that I want to set in my class initializer.
#property (assign, nonatomic) BOOL isEditMode;
- (id)init
{
. . .
[self setValue:NO forKey:isEditMode];
return self;
}
The compiler gives me an "Incompatible integer to pointer conversion" warning. What am i doing wrong here?
The Key-Value Coding method setValue:forKey: only accepts objects as arguments. To set a BOOL, you need to wrap the number in a value object with [NSNumber numberWithBool:NO]. But there's little reason to do that. Key-Value Coding is a roundabout way to accomplish this. Either do self.isEditMode = NO or just isEditMode = NO. The latter is preferable in an init method (because setters can run arbitrary code that might not be desirable before an object is fully set up).
But to elaborate on the first point: The reason Key-Value Coding works this way is because the type system can't represent an argument that's sometimes an object and at other times a primitive value. So KVC always deals with objects and just autoboxes primitive values as necessary. Similarly, if you do [yourObject valueForKey:#"isEditMode"], you'll get back an NSNumber object wrapping the real value.
The correct syntax to set a property is just
self.isEditMode = NO;
If you want to use -setValue:forKey: you'd have to write it as
[self setValue:[NSNumber numberWithBOOL:NO] forKey:#"isEditMode"];
However, there's absolutely no reason to do this in your situation.
That said, since you're in an init method, I would strongly recommend avoiding any property access whatsoever and instead using the ivar directly, as in
isEditMode = NO;
This avoids the possibility of an overridden setter being called (either in this class or a subclass) that makes the assumption that the object has already completed initialization. For this same reason you also want to avoid property access inside of -dealloc.
You can just assign the value directly:
isEditMode = NO;
I think you mean:
self.isEditMode = NO;
If your code does indeed compile (I'm pretty new to Objective-C so I don't know) setValue probably takes a pointer to a string (#"isEditMode", e.g.) and not some other type (isEditMode, e.g.).

Setting the frame.size using the dot operator

I have a UIController and as you all know UIController is associated to a view and you can access it using the getter and setters methods which are synthesized
UIController controller = init code ..
..
controller.view -> this gives me my UIView object which retained and autoreleased, this will be synthesized get method(If at all my synthesized getmethod understanding is correct)
controller.view.frame -> this gives me my CGRect struct
controller.view.frame.size -> CGSize struct
why cannot I assign a value directly to this frame structure
controller.view.frame.size.width = 20;
for the above statement I get this error "lvalue required as left operand of assignment"
This is a normal c dot operator I think it should work.Please enlighten if I am missing anything
Using the dot operator in this situation is using the frame getter method behind the scenes. Since the frame property is a CGRect, which is a simple C struct, frame returns you a copy of the value, not a pointer to the value. Changing it will modify the CGRect you have copied locally on the stack, not the CGRect of your view's frame property. To update the actual frame property you must go through the setter method [yourView setFrame:yourNewFrame]; or yourView.frame = yourNewFrame;.
the easiest to solve that is to set the whole frame again
controller.view.frame = CGRectMake(controller.view.frame.origin.x, controller.view.frame.origin.y, 20, controller.view.frame.size.height);
the reason why this is not working directly is described in James link, it has only getters.
Dot syntax is just syntax sugar.
In this case, this code:
controller.view.frame.size.width = 20;
Is actually this code:
[[controller view] frame].size.width = 20;
In C terms, that's like this:
ViewGetFrame(ControllerGetView(controller)).size.width = 20;
Bottom line is you can't set a subfield of a function result this way. And even if you could, it wouldn't affect the original but only a copy.

Subclassing and Casting in Objective C

I came across a strange problem today. I created a subclass of UIView and added only 1 method to the template code provided by xcode.
#interface FloatView : UIView {
}
- (void)floatTest:(CGFloat)x;
#end
- (void)floatTest:(CGFloat)x {
NSLog(#"float was %f", x);
}
Then in my appDelegate I had code like this:
UIView *floatView = [[FloatView alloc] init];
[floatView floatTest:10.0f];
Pretty simple, right? What should this print out? I thought it would something like "10.0000", but no, it prints out "0.000000".
I wrestled with this for hours, trying to figure out what I was doing wrong, and then I changed the code in my appDelegate to
FloatView *floatView = [[FloatView alloc] init];
[floatView floatTest:10.0f];
Only then, did it print out the expected "10.0000". Why is this so? I've declared FloatView as a subclass of UIView, shouldn't I be able to assign a FloatView object to a UIView pointer without problems?
Even though floatView was declared a pointer to a UIView, it's really a floatView and it should be able to handle the floatTest message? Am I totally off base here?
Actually, polymorphism is working as expected. If it didn't work, nothing would have been printed (in your example, 0.0000 is being printed). The thing is, while your instance actually responds to testFloat:10.0f message, since the compiler can't statically see the method declaration (as UIView class doesn't declare such a method), it assumes that your method takes ... as argument and returns id.
When CGFloat is passed to a method that expects variable number of arguments (...), it's promoted to double. Thus, the receiving method is passed a double argument and thinks it's a float and it doesn't get printed correctly.
You can verify this behavior by changing NSLog line to:
NSLog(#"%f", *(double*)&x);
When the compiler sends the message to FloatView* rather than a UIView*, it can find the exact signature of the method. It can see it really expects CGFloat and doesn't promote the argument to double. As a result, it works correctly.
Additionally, if UIView* contained the method declaration that took a CGFloat, the compiler would call the method appropriately. To summarize, this is not a polymorphism issue; it's a missing method signature issue.

When to use brackets and when to use the period in Objective-C

I'm a new iPhone/Objective-C developer and as I'm going through different tutorials and open source code, I am having a bit of a problem understanding when to use the square brackets "[ ]" and when to use the period " . " for accessing properties/methods of an object.
For example, this code:
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
UIColor *backgroundColor = nil;
if (selected){
backgroundColor = [UIColor clearColor];
} else {
backgroundColor = [UIColor whiteColor];
}
self.todoTextLabel.backgroundColor = backgroundColor;
self.todoTextLabel.highlighted = selected;
self.todoTextLabel.opaque = !selected;
self.todoPriorityLabel.backgroundColor = backgroundColor;
self.todoPriorityLabel.highlighted = selected;
self.todoPriorityLabel.opaque = !selected;
}
Why does [UIColor clearColor] get brackets, but todoTextLabel.backgroundColor get the period?
Could someone explain this easily for me?
The convention I have seen in new code is to use the dot for properties, and always use square brackets for messages/selectors (what you call methods). The dot was introduced in Objective-C 2.0, so the disagreement of information you find online is not entirely unexpected.
It's also entirely possible to use square brackets for everything, still (and I do):
foo = [myObject backgroundColor];
[myObject setBackgroundColor:foo];
is equivalent to
foo = myObject.backgroundColor;
myObject.backgroundColor = foo;
To reiterate, you should not be using the dot for messages, only properties.
To answer your specific question, [UIColor clearColor] belongs in brackets because it is not a property; it's actually a class message to UIColor (+(UIColor)clearColor).
You sound like you come from a Java world, so this might be helpful:
MyObject *foo = [[MyObject alloc] initWithAwesome:YES]; /* MyObject foo = new MyObject(TRUE); */
[foo doSomethingWithNumber:5 andString:"five"]; /* foo.doSomething(5, "five"); */
MyColor *bar = foo.faceColor; /* MyColor bar = foo.faceColor; */
MyColor *baz = [foo faceColor]; /* MyColor baz = foo.faceColor; */
foo.backColor = bar; /* foo.backColor = bar; */
[foo setUndersideColor:baz]; /* foo.undersideColor = baz; */
The "setXXX" and "XXX" messages come from synthesized dynamic properties, and are an Objective-C idiom. The "dot" is simply a shorthand for calling those methods, and is roughly equivalent.
EDIT: Now that I've got some upvotes, time to make some of you reconsider >:)
I never use dots, and neither should you.
I use dot notation for properties because,
for ( Person *person in group.people){ ... }
is a little easier to read than
for ( Person *person in [group people]){ ... }
in the second case readability is interupted by putting your brain into message sending mode, whereas in the first case it is clear you are accessing the people property of the group object.
I will also use it when modifying a collection, for instance:
[group.people addObject:anotherPerson];
is a bit more readable than
[[group people] addObject:anotherPerson];
The emphasis in this case should be in the action of adding an object to the array instead of chaining two messages.
Big Nerd Ranch has some thoughts on the dot notation that are worth reading.
There's also a rebuttal.
By (strong) convention, property accessors are written as methods named after the instance variable for the getter, and the (capitalised) instance variable name prefixed with "set" for the setter (so for instance variable foo you'd have foo and setFoo).
As others have pointed out, as of Objective-C 2.0, if you write object.foo, it will map onto method call [object foo] if getting or [object setFoo: arg] for setting. You can use either form, and some people continue to prefer the full method syntax even when using Objective-C 2.0 exclusively.
A separate, but related, addition to Objective-C 2.0 are the #property/#synthesize/#dynamic keywords for generating the getters and setters. You can mix and match these with dot notation - one does not require the other.
Yep, I just started learning this too:
Unlike other languages, syntax to invoke a method on an object is not objName.someMethod();
It's [objName someMethod]
The dot operator is used to either get or set the value of a property in a class. It's a short way of doing something.
The dot operator, as I have seen it, is always used on an instance of an object whereas the [...] can be used on either an instance of an object or statically (using the class name).
todoTextLabel can use the [] also but using the dot operator is just shorter hand...otherwise you would have to provide parameters, etc, and that's just longer notation.
Hope this helped.