Evgeniy Kleban
Evgeniy Kleban

Reputation: 6940

Understanding getter and setter routine

I'm in process of reading Obj-C book and I'm not fully understand whats going on.

There is code of my app in main.m function:

    Rectangle *myRect = [[Rectangle alloc]init];

    XYPoint *myPoint = [[XYPoint alloc]init];

    [myPoint setX:100 andY:200];

    myRect.origin = myPoint;

    XYPoint *theOrigin = [myRect origin];

    [theOrigin setX:200];
    [theOrigin setY:300];

    NSLog(@"Test %i and %i", theOrigin.x, theOrigin.y);

    NSLog(@"Origin at (%i, %i)", myRect.origin.x, myRect.origin.y);

You see, i insert following code:

 XYPoint *theOrigin = [myRect origin];

        [theOrigin setX:200];
        [theOrigin setY:300];

I made it for purpose, actually, i didn't want that values to be changed. In Rectangle.m file i modified setter method as follow:

-(void)setOrigin:(XYPoint *)pt{ 
    if (!origin){  
        origin = [[XYPoint alloc]init];
        origin.x = pt.x;
        origin.y = pt.y;
    }
}

So, logic is, when origin is not zero, it can't be changed (if i understand correct). But NSLog still output values of 200 and 300, therefore, it changed after first declaration?

When try to modify my XYPoint class like this:

[myPoint setX:50 andY:50];
NSLog(@"Origin at (%i, %i)", myRect.origin.x, myRect.origin.y);

I got same output. Its confusing.

I try to modify getter method like follow (to create a copy and return copy instead):

-(XYPoint*)origin{

    if (origin){
        XYPoint *copy = [[XYPoint alloc]init];
        copy = origin;
        NSLog(@"Copy will be returned");
        return copy;
    }   else {
        return  origin;
    }
}

But it still appears that problem here, and output the same, values keep changing. How to modify getter method to prevent this happening?

Why is that happen? How to prevent this? Any advice would be appreciated, thanks!

Upvotes: 0

Views: 95

Answers (1)

Rob
Rob

Reputation: 437672

You've defined your setter for origin property such that you cannot change it once you set it. But you've defined XYPoint such that it's a mutable class (i.e. you can change the x and y values). So, when you return theOrigin of [myRect origin], you are still able to change its values.


Personally, I would step back from this interface. I am not a fan of a class interface that suggests that you can set some property when you really cannot. I'm also not crazy about the fact that setOrigin is employing something akin to copy memory semantics, but you haven't shared a property definition that makes that intent explicit.

But going back to what I presume was the intent to not let the origin change once it's been set, I'd rather just see you set these properties when the objects are instantiated, but then leave them as readonly so you can be confident that they won't be mutated on you. The end result is a set of classes that are entirely intuitive.

Thus:

@interface XYPoint : NSObject

@property (nonatomic, readonly) CGFloat x;
@property (nonatomic, readonly) CGFloat y;

- (instancetype)initWithX:(CGFloat)x y:(CGFloat)y;

@end

Where

@implementation XYPoint

- (instancetype)initWithX:(CGFloat)x y:(CGFloat)y {
    self = [super init];
    if (self) {
        _x = x;
        _y = y;
    }
    return self;
}

@end

Likewise, I'd be inclined to make the origin of Rectangle to be readonly.

@interface Rectangle : NSObject

@property (nonatomic, readonly) XYPoint *origin;

- (instancetype)initWithOrigin:(XYPoint *)origin;

@end

Where

@implementation Rectangle

- (instancetype)initWithOrigin:(XYPoint *)origin {
    self = [super init];
    if (self) {
        _origin = origin;
    }
    return self;
}

@end

Then once you create your XYPoint and Rectangle objects, you can be confident that the properties will not mutate.

XYPoint *origin = [[XYPoint alloc] initWithX:100 y:200];
Rectangle *rect = [[Rectangle alloc] initWithOrigin:origin];

There are other approaches, but I really don't like your approach of a setter that won't set the value. You can do that, but it's unintuitive. As a developer, you expect that when you set a property, that property actually changes.

Upvotes: 1

Related Questions