Objective-C getter/ setter - objective-c

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.

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.

Calculation/variable returning as zero

I am setting up a basic geometry class where I define a rectangle and can manipulate the width and height along with calculating the area and perimeter. Everything works and outputs fine, except the perimeter and area variables return as zero. I don't know how to set the variable properly within itself or during the #implementation, so I'm sure it is showing the zero from when the variable is first initialized (before the width and height are set).
I'm inexperienced with OOP and ObjC so I may be missing something simple.
#import <Foundation/Foundation.h>
// #interface setup as required.
#interface Rectangle: NSObject
-(void) setWidth: (int) w;
-(void) setHeight: (int) h;
-(int) width;
-(int) height;
-(int) area;
-(int) perimeter;
-(void) print;
#end
// #implementation setup for the exercise.
#implementation Rectangle {
int width;
int height;
int perimeter;
int area;
}
// Set the width.
-(void) setWidth: (int) w {
width = w;
}
// Set the height.
-(void) setHeight: (int) h {
height = h;
}
// Calculate the perimeter.
-(int) perimeter {
return (width + height) * 2;
}
// Calculate the area.
-(int) area {
return (width * height);
}
-(void) print {
NSLog(#"The width is now: %i.", width);
NSLog(#"The height is now: %i.", height);
NSLog(#"The perimeter is now: %i.", perimeter);
NSLog(#"The area is now: %i.", area);
}
#end
int main(int argc, const char * argv[])
{
#autoreleasepool {
// Create an instance of Rectangle.
Rectangle *theRectangle;
theRectangle = [Rectangle alloc];
theRectangle = [theRectangle init];
// Use the designed methods.
[theRectangle setWidth: 100];
[theRectangle setHeight: 50];
[theRectangle print];
}
return 0;
}
Short answer:
Call your object methods like this:
[self perimeter];
// as in
NSLog(#"The perimeter is now: %i.", [self perimeter]);
instead of just
perimeter
which accesses the variable with that name, instead of calling the method you've defined.
Longer answer:
There are several things in your code that can be improved:
You should use properties instead of ivars and methods to get and set them. A property declared like this: #property (nonatomic) int width; will give you a getter and a setter, created implicitly by the compiler. So then you can do either of these to set a value:
theRectangle.width = 100;
// is the same as:
[theRectangle setWidth:100];
You can override your getters and setters too. You could also create readonly properties, e.g.
#interface Rectangle: NSObject
#property (nonatomic) int width;
#property (nonatomic) int height;
#property (nonatomic, readonly) int perimeter;
#end
#implementation Rectangle
- (int)perimeter
{
return self.width * self.height * 2;
}
#end

Why can't I use direct instance variable from parent class

#interface rectangle: NSObject
#property int width, height;
{
-(int) area;
-(int) perimeter;
-(void) setWidth: (int) w andHeight: (int) h;
}
#end
#implementation rectangle
#synthesize width, height;
...
...
#end
I made a square subclass of rectangle
#interface square: rectangle
-(void) setSide: (int) s;
-(int) side;
#end
#implementation square
-(void) setSide: (int) s
{
[self setWidth: s andHeight: s];
}
-(int) side
{
return self.width;
}
#end
My main question is this: Why can't I just do this
return width;
when I want to get the side of my square object.
I thought
#property int width, height;
is just a simplified from
#interface rectangle: NSObject
{
int width;
int height;
}
//getter/setter methods
...
#end
and in the book, if an instance variable is declared in #interface, it is inherited by its subclass. But, apparently,
return width;
doesn't seem to work. Why is this happening?
The problem is that synthesize of properties is part of the implementation, not the interface. The subclass can only rely on the interface.
For example, the #synthesize could have specified a different instance variable name (e.g. #synthesize width = _my_funky_width;) and the subclass would have no way of knowing what the actual instance variable was.

i try to understand initializers in obj-c and i can't

I try to understand how to work simple init funcion and I don't know where I have made a mistake. Can somebody assist?
Rectangle.h
#interface Rectangle : NSObject
{
int width;
int height;
}
-(id)initObject;
#end
Rectangle.m
#implementation Rectangle
-(id)initObject{
if (self = [super init]) {
height = 5;
width = 7;
}
return self;
}
#end
And in ViewController.h i import Rectangle.h, declare *rect object and in .m i execute(? run?) initObject.
ViewController.h
#import <UIKit/UIKit.h>
#import "Rectangle.h"
#interface ViewController : UIViewController
{
Rectangle *rect;
}
#end
ViewController.m
-(void)viewDidLoad
{
rect = [[Rectangle alloc] initObject];
NSLog(#"%#", rect);
[super viewDidLoad];
}
initObject return me:
2011-11-21 09:43:02.625 initializers[43693:f803] <Rectangle: 0x6ab1660>
The only problem with your code that I can see is you called your initializer -initObject for no good reason. It's not taking any parameters at all, so you really should just call it -init like every other parameterless initializer in the system.
As for the log output, I imagine your confusion lies in the fact that it says <Rectangle: 0x6ab1660>. This is perfectly normal. The default implementation of -description (the method that returns this output) is the name of the class of the object followed by the object's address. In other words, -[NSObject description] is likely to be implemented something like the following:
- (NSString *)description {
return [NSString stringWithFormat:#"<%#: %p>",
NSStringFromClass([self class]),
self];
}
This means that instance variables of your object are not going to be printed. A number of built-in classes do print their instance variables when logged, but this was implemented specifically for that class and is not a generic mechanism. If you want to verify that your Rectangle object is correct, you could implement -description like so:
- (NSString *)description {
return [NSString stringWithFormat:#"<%#: %p width=%d, height=%d>",
NSStringFromClass([self class]),
self,
width,
height];
}
No error! Since your Rectangle class has no description method, calling NSLog(#"%#", rect); will return the class of the object, followed by its address in memory.
If you want to print width and height of the rectangle you may use something like:
in Rectangle.h
#interface Rectangle : NSObject
{
int width;
int height;
}
-(id)initObject;
#property int width, height;
#end
in Rectangle.m
#implementation Rectangle
#synthesize width, height;
-(id)initObject{
if (self = [super init]) {
height = 5;
width = 7;
}
return self;
}
#end
and then call
NSLog(#"width=%d, height=%d", [rect width], [rect height]);

Error with getter method in Objective-C

I am following along with a series of web tutorials relating to Objective-C and am now getting a "Accessing unknown origin getter method" error when i try to build my program (origin being a member of a Rectangle class that I created).
Here is my class titled PointXY:
#import <Foundation/Foundation.h>
#interface PointXY : NSObject
{
int x;
int y;
}
//Setters and Getters
#property int x;
#property int y;
//Methods
- (void) setXY : (int) xCO : (int) yCO;
#end
I then define a rectangle class, that has a member that is of type PointXY:
#import <Foundation/Foundation.h>
#class PointXY;
#interface rectangle : NSObject
{
float width;
float height;
PointXY * origin;
}
//Setters and Getters
#property float width, height;
//Instance Methods
- (float) getArea;
- (float) getPerimeter;
//We already have setters and getters defined for width
//and height. The below method is for illustration purposes
- (void) setHW: (float) h : (float) w;
//Methods to set and get origin values
- (PointXY *) getOrigin; //Returns a PointXY object
- (void) setOrigin : (PointXY *) point;
#end
I get the error in main, if i try to access the x or y property of my origin member via my NSLog statement:
#import <Foundation/Foundation.h>
#import "rectangle.h"
#import "PointXY.h"
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
//Create an object
rectangle * myRectangle = [[rectangle alloc]init];
PointXY * rOrigin = [[PointXY alloc]init];
[rOrigin setXY:100 :100];
myRectangle.origin = rOrigin;
NSLog(#"The origin for the rectangle is %i, %i", myRectangle.origin.x, myRectangle.origin.y);
[pool drain];
return 0;
}
I understand that one cannot access the members without either explicitly defining a synthesized accessor or by creating a method to do just that and was surprised to see the author of the tutorial do the above with no issue.
Is the above even possible? Can I access myRectangle.origin.x without origin being synthesized in myRectangle or do I have something set up incorrectly.
Thanks for your time.
Origin is an instance variable you need to create an #property for it and synthesize it as you already know.
//Setters and Getters
#property float width, height;
#property PointXY *origin;
But without the property you could access the origin by doing this rectangle->origin but that defeats the purpose of encapsulation.
Edit- origin will need to be defined as #public or #package