Reputation: 113
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
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
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:
struct
;@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);But under the hood an Objective-C class is implemented as a C struct
...
HTH
Upvotes: 2
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
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:
Hope that helps.
Upvotes: 0
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