I Have read the already posted questions extensively and can't quite find the answer I'm looking for.
I fully understand the concept of using the @syntesize
directive to create getter and setter methods (i.e. if i had @property int width
and @synthesize width
, I am inadvertently creating a getter method of width
and a setter method of setWidth:
).
However, when I am not using the @synthesize
directive but am declaring instance variables in the @implementation
section that are objects, I do not fully understand how the accessor methods work. This is what I do not understand about the following code:
1) in main
where it says:
NSLog(@"Origin at (%i, %i)", myRect.origin1.x, myRect.origin1.y);
It appears to me as if it would be calling the [[myRect origin1] x]
method which would first determine that [myRect origin1]
returns origin
and would then immediately call [origin x]
as a result (and then do the same for y
). Now, what throws me off is the fact that if I were to change the name of the getter method
-(XYpoint *) origin1;
contained within Rectangle.h to
-(XYpoint *) origin2;
the program gets tons of errors and ceases to compile. Note: I also changed the name of this method everywhere it is referenced including changing the preceding code in main to
NSLog(@"Origin at (%i, %i)", myRect.origin2.x, myRect.origin2.y);
However if I also change the name of the setter method from:
-(void) setOrigin1: (XYpoint *) pt
to:
-(void) setOrigin2: (XYpoint *) pt
then everything works as it did before. It seems to me it only works correctly when my getter and setter are both named in the x
setX
naming convention. I supposed this is mainly what I need explained:
A) If I create an instance variable that happens to be an object (like 'origin' in this case) must I create getter and setter methods for it?
B) Can I create a getter method but not a setter method or vice versa
C) Is it mandatory that if I do create both a getter and setter method for 'origin' that they both be named in the x
setX
manner. In this case as -(XYpoint *) origin1
and -(void) setOrigin1: (XYpoint *) pt
. As in if I change the name of the getter I must change the name of the setter accordingly?
Here is all of the code:
Rectangle.h:
#import <Foundation/Foundation.h>
@class XYpoint;
@interface Rectangle : NSObject
@property int width, height;
-(XYpoint *) origin1;
-(void) setOrigin1: (XYpoint *) pt;
-(void) setWidth: (int) w andHeight: (int) h;
-(int) area;
-(int) perimeter;
@end
Rectangle.m:
#import "Rectangle.h"
@implementation Rectangle
{
XYpoint *origin;
}
@synthesize width, height;
-(void) setWidth:(int) w andHeight:(int)h
{
width = w;
height = h;
}
-(void) setOrigin1: (XYpoint *) pt
{
origin = pt;
}
-(int) area
{
return width * height;
}
-(int) perimeter
{
return (width + height) * 2;
}
-(XYpoint *) origin1
{
return origin;
}
@end
XYpoint.h:
#import <Foundation/Foundation.h>
@interface XYpoint : NSObject
@property int x, y;
-(void) setX: (int) xVal andY: (int) yVal;
@end
XYpoint.m:
#import "XYpoint.h"
@implementation XYpoint
@synthesize x,y;
-(void) setX: (int) xVal andY: (int) yVal
{
x = xVal;
y = yVal;
}
@end
main.m:
#import <Foundation/Foundation.h>
#import "Rectangle.h"
#import "XYpoint.h"
int main (int argc, const char * argv[])
{
@autoreleasepool {
Rectangle *myRect = [[Rectangle alloc] init];
XYpoint *myPoint = [[XYpoint alloc] init];
[myPoint setX: 100 andY: 200];
[myRect setWidth: 5 andHeight:8];
myRect.origin1 = myPoint;
NSLog(@"Rectangle w = %i, h = %i", myRect.width, myRect.height);
NSLog(@"Origin at (%i, %i)", myRect.origin1.x, myRect.origin1.y);
NSLog(@"Area = %i, Perimeter = %i", [myRect area], [myRect perimeter]);
}
return 0;
}
You may use lombok - to manually avoid getter and setter method. But it create by itself. The using of lombok significantly reduces a lot number of code.
Getters and Setters play an important role in retrieving and updating the value of a variable outside the encapsulating class. A setter updates the value of a variable, while a getter reads the value of a variable.
1. The getter and setter method gives you centralized control of how a certain field is initialized and provided to the client, which makes it much easier to verify and debug. To see which thread is accessing and what values are going out, you can easily place breakpoints or a print statement. 2.
The concept of getters and setters in C++ is the professional way to access the data from a private specifier. In the concept of encapsulation, we hide the data from users, and to modify that data we use a function of set and get C++. With some practice, you will be able to get on top of it in no time!
A) If I create an instance variable that happens to be an object (like 'origin' in this case) must I create getter and setter methods for it?
No. If you declare a property, you'll need to either provide your own accessors or use the @synthesize directive to create them. But you can have all the instance variables you like without having accessors for them.
B) Can I create a getter method but not a setter method or vice versa
Yes, you can provide just the getter if you declare your property readonly
.
C) Is it mandatory that if I do create both a getter and setter method for 'origin' that they both be named in the x setX manner. In this case as -(XYpoint *) origin1 and -(void) setOrigin1: (XYpoint *) pt. As in if I change the name of the getter I must change the name of the setter accordingly?
You can provide your own names for the accessors, but you should stick with the usual convention if you want your class to be key value coding compliant for the property in question:
@property (getter=isBar, setter=setBar) int bar;
You most likely forgot to change the method names in the header or implementation files. It's perfectly valid to have read-only properties (without setter methods).
The best practice if you have an object property that you want to access using the dot-notation (ie. myRect.origin1
), is to make sure you define the corresponding property in the header file, ie. include a line such as:
@property(readonly) XYPoint *origin1; // for read only properties
@property(retain) XYPoint *origin1; // for read/write properties
Use them even if you don't use @synthesize
, and use them instead of the normal method declarations in the header file. These lines don't actually create getters and setters, they just inform the compiler that your class has these properties. The compiler will then expect getters (and setters if you don't use readonly) named -origin1
and -setOrigin1
. The names of the setters/getters are important (see Apple's Documentation on Key-Value Coding for details)
You should also be aware of Cocoa's memory management guidelines: Unless you are using Automatic reference counting, your Rectangle class is responsible for retaining or copying the XYPoint object in the setter. [EDIT]: I just realised that you are obviously using ARC since you use the @autoreleasepool
syntax.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With