在Objective-C中理解自我

时间:2012-02-15 03:05:41

标签: objective-c object pointers self super

以下代码来自Objective-C中iPhone开发的iTunes U课程。我已经阅读了Apple文档,除了self之外,它都非常清楚。我有点理解自我是指向自己的指针,但究竟是什么意思呢?在下面的代码中,自我意味着什么? self.topSpeed和self.nearestWormhole在实现文件中有什么区别,或者在两种情况下self都指向同一个东西? self.topSpeed是指Planet *和self.nearestWormhole是指虫洞*?感谢任何回答的人,我已经学会了C,现在正在努力学习OOP,所以任何输入都会受到赞赏。

(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

5 个答案:

答案 0 :(得分:4)

self(或C ++中的this)指的是执行该方法的对象(或“正在调用该方法的对象”)。

假设我有一个有三个人的房间,Arthur,Betty和Ziggy,以及一盒帽子。我们还定义了

  亚瑟的老师是贝蒂。

     贝蒂的老师是Ziggy。

     

Ziggy没有老师。

我想向所有三个人提供以下指示:

1。戴上Ziggy的头。

这很简单。 “Ziggy”对Arthur,Betty甚至Ziggy来说都是同一个人。无论是谁遵循这一指示,同一个人都会收到帽子。

2。如果你有老师的头,请戴上帽子。

这条指令会产生不同的影响,具体取决于谁跟随它,因为老师指的是三人中每一人的不同。但每个人都可以问自己“如果我有老师,谁是我的老师?”并找到那个人。

但接下来我想要的是亚瑟在亚瑟的头上戴上帽子,贝蒂戴上帽子戴上贝蒂的头,而Ziggy戴上帽子 Ziggy的头。我们不能通过名字(如Ziggy)来引用那个人,因为这取决于谁在做这件事。假设我们把它视为“老师”并建立一个变量“foo”,这样Arthur的foo就是Arthur,而Betty的foo就是Betty ......但是我们真正表达的想法应该很明显Ziggy的foo是Ziggy,而Jack的foo将是杰克,而Skip的foo将是Skip ...我们真的需要建立一个“foo”吗?没有! 每个人都有一个foo:这是你的自我 。因此,让我们定义一个隐式变量“self”,它不会在任何地方声明,但总是指执行动作的人。

3。把帽子放在自己的头上。

这适用于Arthur,Betty,Ziggy,甚至Jack。它适用于任何人。

在您的代码中self指的是需要访问topSpeed的Spaceship。你创建了许多太空飞船,每个人都需要知道那个存在的太空飞船的topSpeed(我们知道它确实因为它正在调用方法)但没有名字(比如myWingman.topSpeed) - 一个是self

答案 1 :(得分:2)

克里斯蒂安,我会为你提供一个不同的方法。你说你知道C,让我们从那里开始吧。如果你需要实现分数,你可以使用struct,让我们假设你出于某种原因决定动态分配你的分数。你有这样的事情:

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;
}

你会像以下一样使用它:

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

这是ADT - 抽象数据类型 - 编程风格。您声明一个数据类型,其内容是私有的(“抽象”部分)到您将提供的函数,以及一堆函数。

在基础层面上,面向对象编程所做的只是颠倒你对此的看法。而不是“调用函数multiplyFraction传递两个分数”,你说“将消息multiplyFraction和一个分数传递给分数”。使用Objective-C语法在上面的最后一行:

Fraction *onethird = multiplyFraction(half, twothirds);

变为:

Fraction *onethird = [half multiplyFraction:twothirds];

在幕后,这个“方法发送”只是变成了一个“函数调用” - Objective-C做了一些工作来定位multipleFraction,然后调用它传递它两者 {{ 1}}和half

几乎就在那里!现在要匹配调用的更改语法Objective-C也会更改twoThirds定义的语法:

multiplyFraction

但是你为- (Fraction *) multiplyFraction:(Fraction *)right { Fraction *result = [Fraction new]; // allocate result->numerator = ????->numerator * right->numerator; result->denominator = ????->denominator * right->denominator; return result; } 写了什么?正如您将看到语法仅命名第二个参数(????),没有为第一个参数指定名称(right)。 Objective-C 隐藏传递此参数,每个方法至少需要一个参数 - 它是发送方法的“对象”(而不是“ADT”)。它需要一个名称,以便您可以引用它,该名称为left

self

这基本上是它 - - (Fraction *) multiplyFraction:(Fraction *)right { Fraction *result = [Fraction new]; // allocate result->numerator = self->numerator * right->numerator; result->denominator = self->denominator * right->denominator; return result; } 是第一个参数的名称。

面向对象语言构建于此基础之上,例如:

  • 他们可以直接访问“实例”变量 - 原始self的“字段”;
  • 他们改变了一些语法 - 例如struct取代@interface...;而不是列出标题中类型(struct...)之后的方法(函数),它们列在里面(`@interface);
  • 他们通常会添加继承(虽然有些ADT语言也有这种继承);

但在幕后,Objective-C类 实现为C struct ......

HTH

答案 2 :(得分:0)

Objective C强调使用getter和setter。为了简化操作,它甚至可以在@synthesize时生成getter和setter。

所以

self.topSpeed

访问topSpeed的getter。如果省略“self”部分,那么它等同于直接访问实例变量(ivars)(不好的做法)。

在变量名之前加上下划线的原因还在于明确区分实例变量和实例变量的getter。这样,我们就不会在没有“self”的情况下意外地引用topSpeed。

您需要使用self来访问除以下所有地方的变量:

  • 初始化
  • 的dealloc

希望有所帮助。

答案 3 :(得分:0)

self确实是对运行代码的类实例的指针引用。在这种情况下,self将是对Spaceship类实例的引用。

当您在类方法中引用self时(这是非常可能且可接受的行为),您实际上是引用表示该类的单例实例。您也可以通过调用[Spaceship class]来获取此单例实例。实际上,当你需要分配一个新实例时,你可以在工厂方法中使用这样的self

你似乎更困惑的是关于其他类的语法。你问:

  

self.topSpeed是否指的是Planet *和self.nearestWormhole指的是   虫洞*?

Wormhole *nearestWormhole表示Wormhole类的实例,名为nearestWormhole。因此,当您使用self.nearestWormhole时,这是指向Workhole类实例的指针。在Spaceship类中,您实际上可以使用_nearestWormhole或self.nearestWormhole来访问该指针。其他类可能会调用spaceship.nearestWormhole之类的东西,它正在使用访问器。

答案 4 :(得分:-1)

'self'指的是当前类的实例,即在您的示例中它将引用Spaceship类的实例。因为'self'总是引用类的一个实例,所以不可能在类方法中调用self。