Cristian Contreras
Cristian Contreras

Reputation: 113

Understanding self in Objective-C

The code below is from an iTunes U course on iPhone dev in Objective-C. I've read the Apple documentation and it's all very very clear with the exception of self. I sort of understand self to be a pointer to myself, but what exactly does that mean? In the code below what exactly does self mean? What is the difference between self.topSpeed and self.nearestWormhole in the implementation file or does self refer to the same thing on both occasions? Does self.topSpeed refer to Planet * and self.nearestWormhole refer to Wormhole * ? Thanks to anyone who answers, I've learned C and now trying to learn OOP so any input is appreciated.

(Header file)
#import "Vehicle.h"
#import "Planet.h"
@interface Spaceship : Vehicle
@property (nonatomic) double topSpeed;
- (void)orbitPlanet:(Planet *)aPlanet
         atAltitude:(double)km;
@end





(Implementation file)
#import "Spaceship.h"
@interface Spaceship()
@property (nonatomic, strong) Wormhole *nearestWormhole;
@end

@implementation Spaceship
@synthesize topSpeed = _topSpeed;
@synthesize nearestWormhole = _nearestWormhole;

- (void)setTopSpeed:(double)speed
{
    if ((speed < 1) && (speed > 0)) _topSpeed = speed;
}

- (void)orbitPlanet:(Planet *)aPlanet atAltitude:(double)km
{
    double speed = self.topSpeed;
    if (speed > MAX_RELATIVE) speed = MAX_RELATIVE;
    [self.nearestWormhole travelToPlanet:aPlanet
                                 atSpeed:speed];
}
@end

Upvotes: 5

Views: 4980

Answers (5)

Paul Richter
Paul Richter

Reputation: 6311

self (or this in C++) refers to the object which is executing the method (or "on which the method is being invoked").

Suppose I have a room with three people, Arthur, Betty, and Ziggy, and a box of hats. We also define that

Arthur's teacher is Betty.

Betty's teacher is Ziggy.

Ziggy does not have a teacher.

I want to give the following set of instructions to all three people:

1. Put a hat on Ziggy's head.

This is pretty easy. "Ziggy" means the same person to Arthur, Betty, and even Ziggy. No matter who follows this instruction the same person receives the hat.

2. Put a hat on the head of your teacher, if you have one.

This instruction will have a different effect depending on who's following it, because teacher refers to someone different for each of the three. But each can ask him/herself "who is my teacher, if I have one?" and find that person.

But the next thing I want is for Arthur to put a hat on Arthur's head, Betty to put a hat on Betty's head, and Ziggy to put a hat on Ziggy's head. We can't refer to that person by name (like Ziggy) because it depends on who is doing it. Suppose we treat it like "teacher" and establish a variable "foo" such that Arthur's foo is Arthur, and Betty's foo is Betty… but it should be obvious that the idea we are really expressing is that Ziggy's foo is Ziggy, and Jack's foo would be Jack, and Skip's foo would be Skip… do we really need to establish a "foo"? No! Everyone has a foo: it's your self. So let's define an implicit variable "self" that is not declared anywhere but always refers to the person carrying out the action.

3. Put a hat on the head of your self.

This works for Arthur, Betty, Ziggy, and even Jack. It works for anyone.

In your code self refers to the Spaceship whose topSpeed needs to be accessed. You create many Spaceships and each needs to know the topSpeed of that one Spaceship which exists (we know it does because it's calling the method) but has no name (like myWingman.topSpeed) - one's self.

Upvotes: 4

CRD
CRD

Reputation: 53010

Cristian, I'll offer you a different tack on this. You say you know C, let's start there. If you needed to implement fractions you'd use a struct, and let's assume for some reason you decide to dynamically allocate your fractions. You have something like this:

typedef struct { int numerator; int denominator; } Fraction;

Fraction *newFraction(int numer, int denom)
{
   Fraction *result = (Fraction *)malloc(sizeof(Fraction)); // allocate
   result->numerator = numer;
   result->denominator = denom;
   return result;
}

Fraction *multiplyFraction(Fraction *left, Fraction *right)
{

   Fraction *result = (Fraction *)malloc(sizeof(Fraction)); // allocate
   result->numerator = left->numerator * right->numerator;  // multiple (ignoring reduction)
   result->denominator = left->denominator * right->denominator;
   return result;
}

And you'd use it like:

Fraction *half = newFraction(1, 2);
Fraction *twothirds = newFraction(2, 3);

Fraction *onethird = multiplyFraction(half, twothirds); // results is 2/6 as we don't reduce in this example

This is the ADT - abstract data type - style of programming. You declare a data type whose content is private (the "abstract" part) to the functions you will provide, and a bunch of functions.

At the basic level what object-oriented programming does is just invert the way you look at this. Instead of "call function multiplyFraction passing two fractions" you say "pass the message multiplyFraction, along with a fraction, to a fraction". Using Objective-C syntax the last line above:

Fraction *onethird = multiplyFraction(half, twothirds);

becomes:

Fraction *onethird = [half multiplyFraction:twothirds];

Under the hood this "method send" just becomes a "function call" - Objective-C does a bit of work to locate multipleFraction and then calls it passing it both half and twoThirds.

Almost there! Now to match the changed syntax for the call Objective-C also changes the syntax of the definition of multiplyFraction:

- (Fraction *) multiplyFraction:(Fraction *)right
{

   Fraction *result = [Fraction new]; // allocate
   result->numerator = ????->numerator * right->numerator;
   result->denominator = ????->denominator * right->denominator;
   return result;
}

But what do you write for ????. As you'll see the syntax only names the second parameter (right), there is no name given for the first (which was left). Objective-C hides the passing of this parameter, every method takes at least one parameter - it is the "object" (rather than "ADT") that the method is sent to. It needs a name so you can refer to it, that name is self:

- (Fraction *) multiplyFraction:(Fraction *)right
{

   Fraction *result = [Fraction new]; // allocate
   result->numerator = self->numerator * right->numerator;
   result->denominator = self->denominator * right->denominator;
   return result;
}

And this is essentially it - self is the name of the first argument.

Object-oriented languages build upon this base, for example:

  • they had direct access to "instance" variables - the "fields" of the original struct;
  • they change some more syntax - e.g. @interface... replaces struct...; and rather than list the methods (functions) after the type (struct) in the header they are listed inside of it (the `@interface);
  • they usually add inheritance (though some ADT languages have that as well);
  • etc.

But under the hood an Objective-C class is implemented as a C struct...

HTH

Upvotes: 2

Jared Egan
Jared Egan

Reputation: 1288

self is indeed a pointer reference to the instance of the class that is running the code. In this case, self would be a reference to an instance of the Spaceship class.

When you reference self in a class method (which is very possible and an acceptable behavior), you are actually referencing a singleton instance representing the class. You can also get this singleton instance by calling [Spaceship class]. In practice, you'd use self like this mostly in factory methods when you need to allocate a new instance.

What you seem more confused about is syntax regarding other classes. You asked:

Does self.topSpeed refer to Planet * and self.nearestWormhole refer to Wormhole * ?

Wormhole *nearestWormhole represents an instance of the Wormhole class, named nearestWormhole. So, when you use self.nearestWormhole, that is a pointer to a instance of the Workhole class. Inside the Spaceship class you could actually use _nearestWormhole or self.nearestWormhole to access that pointer. Other classes might call something like spaceship.nearestWormhole, which is using the accessor.

Upvotes: 0

Ravi
Ravi

Reputation: 4019

Objective C emphasizes using getters and setters. To make things simpler, it even generates getters and setters when you @synthesize something.

So

self.topSpeed

accesses the getter for topSpeed. If you omit the "self" part, then it is equivalent to accessing the instance variable(ivars) directly (bad practice).

The reason for having a underscore before the variable name is also to make a clear differentiation between instance variable and the getter for the instance variable. This way, we cannot accidentally refer to topSpeed without "self".

You need to use self to access variable in all places except:

  • init
  • dealloc

Hope that helps.

Upvotes: 0

Wolfgang Schreurs
Wolfgang Schreurs

Reputation: 11834

'self' refers to the instance of the current class, i.e. in your example it would refer to an instance of the Spaceship class. Because 'self' always refers to an instance of the class, it's not possible to call upon self in class methods.

Upvotes: -1

Related Questions