views:

253

answers:

3

In a project I'm creating, I have various classes. One of my classes has an instance of NSMutableArray that holds objects of another one of my classes. I thought I had a firm understanding on this topic, but somehow it got jumbled up in my mind again.

When initializing an instance of this class, I have this initilize method:

- (MMShowMovement *) initWithMovementName: (NSString *) name andNumber: (NSInteger) number {

 if( [super init] ) {

  [self setMovementTitle: name];
  [self setMovementNumber: number];

  [self setDotArray: [[NSMutableArray alloc] init]];

 }

 return self;

}

Later on, after an instance of this class is created, I can add objects to the NSMutableArray "dotArray." Here is that method.

- (void) addDot: (MMDot *) dot {

 [dotArray addObject: dot]; 

}

(I know, its simple) I'm wondering, when I use "dotArray" in this method, I am accessing the dotArray object for the instance of the class for which this method has been invoked, correct? Or should I use the self keyword here also?

- (void) addDot: (MMDot *) dot {

 [[self dotArray] addObject: dot]; 

}

Honestly, I'm not really sure. I believe it is the former, but I'm unsure as to why. And it is not necessary to use the self keyword in this method, why do I have to use it in the initializer to access the object?

+2  A: 

[self dotArray] calls the "dotArray" selector (method) of the object. If there is no such method, you'll get an error. You cannot access the instance variable this way, unless it's a property and you've synthesized this getter method for it.

[dotArray addObject] simply accesses the variable and calls a built-in method that is specified by NSMutableArray.

[self setMovementTitle:], [self setMovementNumber:] and [self setDotArray:] are all method calls. You always need an object reference for method calls.

In init, you may as well have said [dotArray addObject] (after initing the variable, of course).

Jaanus
Do you mean that he could have written `dotArray = [[NSMutableArray alloc] init]` in `-(id)init`
swegi
swegi: yes, maybe, although maybe setDotArray also does something else.
Jaanus
+2  A: 

Usually we'll write

self = [super init]  

Because super's initialization method might return an object that’s not the same as the one that was allocated. So that's why we use self in initxxx method and we don't need to use self in other kinds of methods.

I learned this stuff clearly from the book Learn Objective-C on the Mac, Chap 10 Object Initialization, Mark Dalrymple and Scott Knaster, Apress.

A excerpt from the book:
instance variables are found at a memory location that’s a fixed distance from the hidden self parameter. If a new object is returned from an init method, we need to update self so that any subsequent instance variable references affect the right places in memory.

yehnan
This makes sense. Thanks! I was rereading through parts of the Kochan book trying to straighten it out again..
Matt Egan
Maybe you can also check the definitive document: The Objective-C 2.0 Programming Language from Apple Developer website, especially Ch3 Allocating and Initializing Objects.
yehnan
+1  A: 

self is a pointer to the current receiver - It refers to the object that received a message.
You can use self to get access to the object that performs the current method.

In your case, this means that if object X of type MMShowMovement receives an addDot: message, self contains a pointer to X.
You can access dotArray in three different ways:

[dotArray addObject:dot]; //directly access the instance variable dotArray
[[self dotArray] addObject:dot]; //access dotArray with an accessor method
//--or--
[self.dotArray addObject:dot]; //access dotArray with an accessor method using dot-syntax

If you are using automatic KVO notifications, you have to use the accessors (instead of directly manipulating the ivar) to trigger notifications.
To ensure that a variable is accessed via its accessor method, you have to prefix self.

weichsel