Objective-c – Setting nested objects

cocoaobjective c

I am just trying to make sure I am getting things right as I move forward with Objective-C, two quick questions if I may:

(1) Am I accessing the Position object correctly from within Rectangle? am I right to access the Position object contained within by the pointer I set in the init, or is there a better way?

(2) In [setPosX: andPosY:] Which of the two ways of setting the Position instance variables is best, or does it really not matter?

// INTERFACE
@interface Position: NSObject {
    int posX;
    int posY;
}
@property(assign) int posX;
@property(assign) int posY;
@end

@interface Rectangle : NSObject {
    Position *coord;
}
-(void) setPosX:(int) inPosX andPosY:(int) inPosY;

// IMPLEMENTATION
@implementation Rectangle
-(id) init {
    self = [super init];
    if (self) {
        NSLog(@"_init: %@", self);
        coord = [[Position alloc] init];
        // Released in dealloc (not shown)
    }
    return(self);
}
-(void) setPosX:(int) inPosX andPosY:(int) inPosY {
    //[coord setPosX:inPosX];
    //[coord setPosY:inPosY];
    coord.posX = inPosX;
    coord.posY = inPosY;
}

EDIT_01

Do I then call -(id)initWithX:andY: from the Rectangle object when I init it? and if so how do I go about setting posX and posY from within main()? or do I replace the init for rectangle with a further -(id)initWithX:andY: and pass the values through?

@implementation Rectangle
-(id) init {
    self = [super init];
    if (self) {
        NSLog(@"_init: %@", self);
        coord = [[Position alloc] initWithX:1234 andY:5678];
    }
    return(self);
}
...

cheers gary

Best Answer

(1) You're accessing it correctly.

(2) In objective-c 2.0, the assignments have identical affect.

Design wise, you would want to make:

-(void) setPosX:(int) inPosX andPosY:(int) inPosY;

...into a method of Position. This encapsulates both the data and the methods related to into one object. So you could have calls like:

coord = [[Position alloc] initWithX:inPosX andY:inPosY];

or [coord setPosX:inPosX andPosY:inPosY];

all much cleaner and easier to maintain.


Edit O1

Do I then call -(id)initWithX:andY: from the Rectangle object when I init it?

That depends on your design. If the coord property is absolutely vital to the Rectangle instance, then you should call it when you initialize a Rectangle instance. You might even write an initializers for Rectangle that takes a position or x and y as input. eg:

-(id) initWithPosition:(Position *) aPos {
    self = [super init];
    if (self) {
        NSLog(@"_init: %@", self);
        coord = aPos;
        // Released in dealloc (not shown)
    }
    return self;
}

You should also write a connivence initializer for the Position class:

-(id) initWithX:(NSInteger) x andY:(NSInteger) y{
     self=[super init];
     self.posX=x;
     self.posY=y;
     return self;
}

You would then call like:

Position *aPos=[[Position alloc] initWithX:100 andY:50];
Rectangle *aRec=[[Rectangle alloc] initWithPosition:aPos];

Or you could write another combination initializer for Rectangle:

-(id) initWithXCoordinate:(NSInteger) x andYCoordinate:(NSInteger) y{
     self=[super init];
     Position *aPos=[[Position alloc] initWithX:x andY:y];
     self.coord=aPos;
     return self;
}

and call it like:

Rectangle *aRec=[[Rectangle alloc] initWithXCoordinate:100 
                                        andYCoordinate:50];   

These are rough examples but you get the idea. Objective-c gives you a lot of flexibility in setting up initializer so you can create any initializers you find convenient.

You do generally want to avoid using actual functions instead of methods inside classes.

Related Topic