Beginners confusion about objective c, assignment, properties etc - objective-c

Sorry I couldn't be more descriptive in the title. I know C++ and C#, and a bit of Java, and I am doing some Objective C tutorials and can't explain what is going on here.
I will show you an example:
Here is the header/interface of the rectangle class:
#import <Foundation/Foundation.h>
#class XYPoint;
#interface Rectangle : NSObject
#property int width, height;
-(int) area;
-(int) perimeter;
-(void) setW:(int)w andH:(int)h;
-(XYPoint *) origin;
-(void) setOrigin:(XYPoint*)pt;
#end
Here is the implementation:
#import "Rectangle.h"
#implementation Rectangle{
XYPoint *origin;
}
#synthesize width, height;
-(void) setW:(int)w andH:(int)h
{
width = w;
height = h;
}
-(int) area{
return width*height;
}
-(int) perimeter{
return (width+height)*2;
}
-(XYPoint *) origin{
return origin;
}
-(void) setOrigin:(XYPoint*)pt{
origin = pt;
}
#end
And here is my main program:
#import <Foundation/Foundation.h>
#import "Rectangle.h"
#import "XYPoint.h"
int main(int argc, const char * argv[])
{
#autoreleasepool {
Rectangle *r = [[Rectangle alloc]init];
XYPoint *p = [[XYPoint alloc]init];
[p setX:100 andY:300];
[r setW:6 andH:8];
r.origin = p;
NSLog(#"Width and height is %i %i", r.width, r.height);
NSLog(#"Origin is at %i,%i", r.origin.x, r.origin.y);
NSLog(#"Arear and perimeter are %i and %i", [r area], [r perimeter]);
}
return 0;
}
The line r.origin = p; confuses me. Exactly which origin is being referred to here? The getter method as defined in the interface, or the actual member variable which is declared in the implementation?
Note origin is not a property.
To be honest I expected an error. The main program should only see the getter method, but it doesn't seem like a getter method that returns something could be on the left hand side of an assignment operator. Or is the system somehow mapping that syntax to a call to setOrigin?
I had expected the only possible way to set the origin would be something like [r setOrigin: p]
I can see how something like r.width = 5 would work, as width as declared in the header as being a property, but I cannot see how r.origin = p works.
Can someone explain what is going on here?
Thanks.

Your guess is right - that syntax, called dot notation, is translated into a call to [r setOrigin:p] by the compiler. The general idea is that just like most other languages, you have getters and setters for object properties; in Objective-C, these are usually written as:
- (type)variableName;
- (void)setVariableName:(type)aVariable;
So long as your own code conforms to these conventions, you can use dot notation to both get and set variables on your classes, and trust that your methods are called.
There's obviously a lot more going on behind the scenes, so I hope this brief explanation is enough for you for now. If you're interested, though, you can look further into:
Synthesizing properties and what actually happens - methods of the form shown above are generated by the compiler, along with instance variables for actual data storage
Key-value coding, which takes advantage of these principles and conventions
Special cases for some types (for example, BOOL variables' getters are usually written as -isVariableName rather than -variableName), and how you can manage them with #property attributes

Yes, property accessors invoked by the dot notation are automagically traansformed to method calls by the compiler; thus
variable = object.property;
is equivalent to
variable = [object property];
and
object.property = variable;
is equivalent to
[object setProperty:variable];

Related

Classes owning their objects

Question:
I understand that origin is an instance variable of the Rectangle class which has the XYPoint type. The origin instance variable has two other instance variables x and y. I don't understand clearly, what the if statement in the rectangle class does?
I believed that the if (! origin) means if the origin is not equal to zero then do the following... Is the origin equal to zero? if yes how is it equal to zero and how is it validated in the if (! origin) statement. In other words what does the if (! origin) statement do?
Is there an instance where the origin is equal to zero? if this occurs, how will my code respond? I know that without the if statement myPoint object will not retain its initial value.
I will also like to know why we used the class directive in rectangle class rather than import. What difference does it make. I also noticed that we didn't import the XYPoint header at the rectangle's implementation. I will be very grateful if anyone is willing to help. Thanks a lot in advance.
NB: Please take a look at my codes below.
*
XYPoint Class
#import <Foundation / Foundation.h>
#interface XYPoint: NSObject
#property int x, y;
-(void) setX: (int) Xval andY: (int) yVal;
#end
#import "XYPoint.h"
#implementation XYPoint
#synthesize x, y;
-(void) setX: (int) Xval andY: (int) yVal
{ x = xVal;
y = yVal;
}
#end
*
Rectangle Class
#import <Foundation/Foundation.h>
#class XYPoint;
#interface Rectangle: NSObject
-(XYPoint *) origin;
-(void) setOrigin: (XYPoint *) pt;
#end
#import "Rectangle.h"
#implementation Rectangle
{
XYPoint *origin
}
-(void) SetOrigin: (XYPoint *) pt
{
if (! origin)
origin = [[XYPoint alloc]init];
origin.x = pt.x;
origin.y = pt.y;
}
-(XYPoint *) origin
{
return origin;
}
#end
Main
#import "Rectangle.h"
#import "XYPoint.h"
int main (int argc, char *argv[])
{
#autoreleasepool {
XYPoint *myPoint = [[XYPoint alloc]init];
[myPoint setX: 100 andY: 200];
myRect.origin = myPoint;
NSLog (#"Origin at (%i, %i)" , myRect.origin.x, myRect.origin.y);
[myPoint setX: 50 andY: 75];
NSLog (#"Origin at (%i, %i)" , myRect.origin.x, myRect.origin.y);
}
#end
Origin at (100, 200)
Origin at (100, 200)
Defining an instance variable creates a pointer that can be used to reference an instance. It doesn't create an instance for you. So, initially there is no origin.
The if statement checks if the origin exists yet, and if not it creates a new one, then the code copies the values from the one passed in the parameter.
Aside: Ideally the point class would be immutable and implement copying so rather than repeatedly creating new instances and updating them you can just copy the passed parameter. Copying would do nothing (return self) in the immutable class and is there only to support the addition of a mutable class in the future.
When being declared an object instance variable is set to nil which is zero in terms of C / Objective-C.
To use an object it must be initialized. That's what the if statement checks and does
if (! origin) // alternative syntax if (origin == nil)
origin = [[XYPoint alloc] init];
means
if the object is nil initialize it. If not skip the line.
The class directive rather than the import statement is used when only the type of the class is mentioned in the code and the header file is not needed.
In your code the import statement is required if the classes are written in separate files.
PS: There are some lowercase / uppercase typos in your code and a semicolon is missing.

What does #property in a header file mean in Obj C?

I'm trying to learn objective C and I'm looking through some simple code to figure it out. Here's an example of a header file:
#import <Foundation/Foundation.h>
#class XYPoint;
#interface Rectangle: NSObject
{
int width;
int height;
XYPoint *origin;
}
#property int width, height;
-(XYPoint *) origin;
-(void) setOrigin: (XYPoint *) pt;
-(void) setWidth: (int) w andHeight: (int) h;
-(int) area;
-(int) perimeter;
#end
Can anyone explain the meaning of the line "#property int width, height;"? Thanks!
The property syntax lets you declare a combination of a getter and a setter in a short syntax. In your code, the declaration creates four methods:
-(int) width;
-(void)setWidth:(int)val;
-(int) height;
-(void)setHeight:(int)val;
There is probably an implementation, too, which ties these methods to their "backing variables" with names width and height defined above; there may also be a #synthesize directive in the .m file.
In the current version of Objective-C the declaration of backing variables is unnecessary: all properties are synthesized by default, but you can provide your own implementations if you wish.
Properties support an alternative way of invoking getter and setter methods in Objective-C: in addition to the standard
int h = [point height];
[point setWidth:123];
you can write
int h = point.height;
point.width = 123;
It is not necessary to declare properties to use the dot syntax: you can call any value-returning method with no arguments or a setter method with a single argument using dot syntax.
It is just a way for other classes to refer to the private iVars declared between { and }.
Basically, it will create a getter and a setter, that, for primitive types like int will look like this:
- (int)width
{
return width;
}
- (void)setWidth:(int)width
{
_width = width;
}
And you can override these 2 methods if you want.
According to the conventions, the underlying instance variables should be prefixed with "_":
#interface Rectangle: NSObject
{
int _width;
int _height;
XYPoint *_origin;
}
If you do not declare them, the compiler does that for you, but be careful, in case you override both the getter and the setter, you need to add this kind of statements in the ".m" file:
#synthesize width = _width;
because in that case the compiler will not generate the "_width" ivar on your behalf.

Missing a fundamental understanding wrt methods

I am an OLD procedural language programmer, trying to learn Obj C. And after pulling out all my hair realize I am missing a fundamental understanding
When I alloc an instance of an object ( myObj), give it some data via methods, and the call a method/send a message to that instance, can the implementation routine assume that all the data in that instance is available?
i.e [myObj doSomeStuff]
can the implementation of doSomeStuff assume that all the instance data of myObj is available or do I need to send in as arguments of all the parts and pieces of myObj that I need?
Ditto on what Luis and rmaddy said. Some of this is best illustrated with an example. Lets consider a Circle class object:
Here is the .h file:
// Circle.h
#import <Foundation/Foundation.h>
#interface Circle : NSObject
{
double radius;
double pi;
}
#property double radius, pi;
-(double) area;
-(double) diameter;
-(double) circumference;
#end
And then the implementation file (note that I have defined instance methods as Luis points out):
// Circle.m
#import "Circle.h"
#implementation Circle
#synthesize radius, pi;
// Initialize with default radius:
- (instancetype)init {
self = [super init];
if (self) {
pi = 3.14159;
NSLog(#"Circle created.");
}
return self;
}
-(double) area {
return pi*radius*radius;
}
-(double) diameter {
return 2*radius;
}
-(double) circumference {
return 2*pi*radius;
}
#end
Now create a circle object in main and send messages to return several relevant quantities:
// main.m
#import <Foundation/Foundation.h>
#import "Circle.h"
int main(int argc, const char * argv[])
{
#autoreleasepool {
Circle *aCircle = [[Circle alloc] init];
[aCircle setRadius:2];
NSLog(#"Area = %f",[aCircle area]);
NSLog(#"Circumference = %f",[aCircle circumference]);
NSLog(#"Diameter = %f",[aCircle diameter]);
NSLog(#"Check pi = %f",[aCircle pi]);
}
return 0;
}
You can see from this example the value of pi is set when the object is created and then is stored as part of the object, available for other calculations.
Note: you wouldn't want to define pi this way in practice, this is just a simple example to illustrate the point.
Note also that I could have set other internal values of the object after it was created, then this data is also available from that point forward, subject to the qualifications pointed out in the post.
Does this make better sense? You should run this code and experiment with the idea until you feel more comfortable with it.
EDIT: At Andrew Madsen's suggestion, updated the accessor methods for area, diameter, and circumference; these should not be prefixed with 'get'
YES, if the method is an instance method (those who starts with a "-" not "+").

Objective-C getter/ setter

I'm trying to work my way through an Objective-C tutorial. In the book there is this example:
#interface
{
int width;
int height;
XYPoint *origin;
}
#property int width, height;
I thought, "hey there's no getter/setter for the XYPoint object. The code does work though." Now i'm going maybe to answer my own question :).
I thinks its because "origin" is a pointer already, and whats happening under the hood with "width" and "height", is that there is going te be created a pointer to them..
Am i right, or am i talking BS :) ??
I just dont get it. here's main:
#import "Rectangle.h"
#import "XYPoint.h"
int main (int argc, char *argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
Rectangle *myRect = [[Rectangle alloc] init];
XYPoint *myPoint = [[XYPoint alloc] init];
[myPoint setX: 100 andY: 200];
[myRect setWidth: 5 andHeight: 8];
myRect.origin = myPoint;
NSLog (#"Rectangle w = %i, h = %i",
myRect.width, myRect.height);
NSLog (#"Origin at (%i, %i)",
myRect.origin.x, myRect.origin.y);
NSLog (#"Area = %i, Perimeter = %i",
[myRect area], [myRect perimeter]);
[myRect release];
[myPoint release];
[pool drain];
return 0;
}
And here's the Rectangle object:
#import "Rectangle.h"
#import "XYPoint.h"
#implementation Rectangle
#synthesize width, height;
-(void) setWidth: (int) w andHeight: (int) h
{
width = w;
height = h;
}
- (void) setOrigin: (XYPoint *) pt
{
origin = pt;
}
-(int) area
{
return width * height;
}
-(int) perimeter
{
return (width + height) * 2;
}
-(XYPoint *) origin
{
return origin;
}
#end
What i dont understand is this line in main: myRect.origin = myPoint; I did not make a setter for it..
BTW thanks for your fast reply's
What i dont understand is this line in main: myRect.origin = myPoint; I did not make a setter for it..
There is both a getter and a setter (collectively referred to as accessors) created for origin in the Rectangle class. If you have a look in the implementation for Rectangle, this is the getter:
-(XYPoint *) origin
{
return origin;
}
and this is the setter:
- (void) setOrigin: (XYPoint *) pt
{
origin = pt;
}
And as of Objective-C 2.0 calling:
myRect.origin = myPoint;
is equivalent to:
[myRect setOrigin:myPoint];
Declaring getters and setters using #property (and then implementing them using #synthesize) is only one way of declaring and creating accessors, and is there for a convenience if you have lots of properties to declare in the class interface. As Schildmeijer said, #property int width is equivalent to declaring two methods:
- (int)width;
- (void)setWidth:(int)newWidth;
Due to the dynamically-bound nature of Objective-C method calls, you don't even have to declare the getter and setter methods in the interface, although it is generally best practice to do so if you are advertising them as publicly available to other classes.
You can think of a property declaration as being equivalent to declaring two accessor methods. Thus
#property int width;
is equivalent to:
- (int)width;
- (void)setWidth:(int)newWidth;
//Rectangle.h
#import <Foundation/Foundation.h>
#interface Rectangle : NSObject
#property int Width;
#property int Height;
-(int)Area;
#end
//Rectangle.m
#import "Rectangle.h"
#implementation Rectangle
#synthesize Width;/*Will create value Width , Setter called"setWidth" and Getter called "Width"*/
#synthesize Height;/*Will create value Height , Setter called"setHeight" and Getter called "Height"*/
-(int)Area
{
return Width*Height;
}
#end
// main.m
#import <Cocoa/Cocoa.h>
#import "Rectangle.h"
int main(int argc, const char * argv[])
{
Rectangle *myRectangle = [Rectangle new];
myRectangle.Width=3;
myRectangle.Height=5;
printf("Area = %d\n",[myRectangle Area]);
//Or
[myRectangle setWidth:5];
[myRectangle setHeight:6];
printf("Area = %d\n",[myRectangle Area]);
}
If you want to make Getter only or rename getter and setter
• readonly
• getter = newGetterName
• setter = new SetterName
example
//Rectangle.h
#import <Foundation/Foundation.h>
#interface Rectangle : NSObject
#property (getter = getWidth) int Width;
#property (readonly) int Height;
#end
You don't say what code is working, or what your expectations are for "working".
The above interface will create simple accessor methods for width and height that can be called from other objects as [object setWidth:1]; or object.width = 1; - these two are analogous.
Origin is some other object type and is a pointer, yes. But you would still want to declare a property for it to generate accessor methods.
Getters and setters are mostly useful if you need to access an instance variable from another class or you're using bindings to get/set them. So my guess would be that you need this functionality for the width and height but not for the origin. Note that the getters/setters do not make pointers out of the integers as you stated might be the reason. Ints are ints and getters/setters do not change that.

what does it mean to set a method as an object or even setting a method argument as an object?

if i have a class named
#interface myClass : NSObject {
int firstnum;
int secondnum;
}
//an a method that looks like this
-(myClass *) myMethod (myClass *) f;
#end
what does that method return as? im used to seeing something like (int) myMethod knowing that it returns an integer. but when its returning an object such as the classes name here what can it possibly return? if you'd like ill write out the whole project im working/studying on. (some methods have been truncated to keep the question simple. but if you'd like ill post it let me know. thnx
#import <Foundation/Foundation.h>
#interface Fraction : NSObject {
int numerator;
int denominator;
}
#property int numerator, denominator;
-(Fraction *) add: (Fraction *) f;
#end
#import "Fraction.h"
#implementation Fraction
#synthesize numerator, denominator;
-(Fraction *) add: (Fraction *) f
{
Fraction *result = [[Fraction alloc] init];
// To add two fractions:
// a/b + c/d = ((a*d) + (b*c)) / (b * d)
result.numerator = numerator * f.denominator + denominator * f.numerator;
result.denominator = denominator * f.denominator;
[result reduce];
return result;
}
#end
The question might be: what is an object? An object is some memory set aside to hold a bunch of values, and it's associated with some methods to interact with those values. You very rarely want to copy that whole chunk of memory. Instead, you pass around pointers to the memory location. So when you pass in or return an object, you are actually just passing around a pointer to the object's location in memory. Pointers are basically just integer values, so that's what's being returned.
In most languages, you don't even have to think about this, and in fact you rarely have to do it in Objective-C either. Just remember that MyClass* is the type of objects that are of class ´MyClass´ and that they respond to all messages that are declared on that class.
That method returns just what it claims to: a pointer to an instance of myClass. In the case of your add: method, it returns the pointer result that you created.
Incidentally, unless you have Garbage Collection enabled, you should add [result autorelease] to that method before returning; otherwise your result fraction will be around forever and you'll leak memory.
CocoaDevCentral's Objective-C Tutorial will help with that memory management, and also might get you more comfortable with methods returning pointers to objects.
it looks like you're working through a copy of the Programming in Objective-C book. In my copy, there is a section at the end of Chapter 13 (Underlying C Language Features) called "How Things Work". I think you are looking for "Fact #2: An Object Variable is Really a Pointer". In your case, the add method is returning a pointer to an instance of the Fraction class. (The asterisk, *, means pointer, the class name before it says what sort of thing it is pointing to) There is more about pointers earlier in the chapter if you don't mind skipping about.
I'm going to be picky and try and rewrite this a bit
#import <Foundation/Foundation.h>
#interface Fraction : NSObject {
// You should really use the recommended type instead of int
NSInteger numerator;
NSInteger denominator;
}
// Don't try and keep these on one line.
// Also, don't depend on default values for assign, retain, or copy when declaring
#property (assign, nonatomic) numerator;
#property (assign, nonatomic) denominator;
// declare the add: function which takes a pointer to a Fraction as a parameter
// and returns a pointer to the restulting fraction
- (Fraction *)add:(Fraction *)aFraction;
#end
#import "Fraction.h"
#implementation Fraction
// Again, don't try and keep these on one line.
// It's easier to visually note the number of synthesised properties matches
// the number of declared properties.
#synthesize numerator;
#synthesize denominator;
// Assume that there is an init function.
- (Fraction *)add:(Fraction *)aFraction
{
Fraction *result = [[Fraction alloc] init];
// To add two fractions:
// a/b + c/d = ((a*d) + (b*c)) / (b * d)
result.numerator = self.numerator * aFraction.denominator
+ denominator * aFraction.numerator;
result.denominator = self.denominator * aFraction.denominator;
[result reduce]; // I assume this is implemented.
return result; // Assuming garbage collection, otherwise use
// return [result autorelease];
}
#end