在 Objective-C 中理解自我
下面的代码来自 iTunes U 的 iPhone 开发课程 Objective-C。我读过苹果文档,除了 self 之外,一切都非常清楚。我有点理解 self 是指向我自己的指针,但这到底是什么意思呢?在下面的代码中,self到底是什么意思?实现文件中 self.topSpeed 和 self.nearestWormhole 之间有什么区别,或者 self 在这两种情况下都引用相同的东西? self.topSpeed 是否指 Planet * , self.nearestWormhole 是否指 Wormhole * ?感谢任何回答的人,我已经学习了 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
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
self
(或 C++ 中的this
)指的是正在执行该方法的对象(或“在其上调用该方法”)。假设我有一个房间,里面住着三个人,亚瑟、贝蒂和齐吉,还有一盒帽子。我们还定义了
我想向所有三个人发出以下一组指示:
1.把帽子戴在 Ziggy 的头上。
这很简单。 “Ziggy”对亚瑟、贝蒂,甚至对齐吉来说都是同一个人。无论谁遵循此指示,同一个人都会收到帽子。
2.如果你有老师的话,请将帽子戴在老师的头上。
这条指令会根据谁遵循它而产生不同的效果,因为老师对三者中的每一个指称不同的人。但每个人都可以问自己“如果我有老师的话,谁是我的老师?”并找到那个人。
但接下来我想要的是 Arthur 将帽子戴在 Arthur 头上,Betty 将帽子戴在 Betty 头上,Ziggy 将帽子戴在 Ziggy 的头。我们不能直接称呼那个人的名字(比如 Ziggy),因为这取决于谁在做这件事。假设我们把它当作“老师”,并建立一个变量“foo”,这样亚瑟的 foo 是亚瑟,贝蒂的 foo 是贝蒂……但很明显,我们真正表达的想法是 Ziggy 的 foo 是 Ziggy,而 Jack 的 foo是 Jack,Skip 的 foo 是 Skip……我们真的需要建立一个“foo”吗?不! 每个人都有一个 foo:这是你的自我。因此,让我们定义一个隐式变量“self”,它没有在任何地方声明,但始终引用执行该操作的人。
3.把帽子戴在自己的头上。
这适用于亚瑟、贝蒂、齐吉,甚至杰克。它对任何人都有效。
在您的代码中,
self
指的是需要访问其 topSpeed 的宇宙飞船。您创建了许多太空飞船,并且每艘太空飞船都需要知道存在的那一艘太空飞船的 topSpeed(我们知道它是因为它正在调用该方法)但没有名称(如 myWingman.topSpeed) - 一个人的self
。self
(orthis
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
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'sself
.克里斯蒂安,我将为你提供一个不同的解决方案。你说你懂C,那我们就从这里开始吧。如果您需要实现分数,您可以使用
struct
,并且假设由于某种原因您决定动态分配分数。你有这样的东西:你会像这样使用它:
这是 ADT - 抽象数据类型 - 编程风格。您声明一个数据类型,其内容对于您将提供的函数和一堆函数来说是私有的(“抽象”部分)。
从根本上讲,面向对象编程所做的只是颠倒了你看待这个问题的方式。你不是说“调用函数multiplyFraction传递两个分数”,而是说“将消息multiplyFraction与一个分数一起传递给一个分数”。使用 Objective-C 语法,上面的最后一行:
变成:
在底层,这个“方法发送”只是变成了“函数调用” - Objective-C 做了一些工作来定位
multipleFraction
然后调用它传递两者half
和twoThirds
。快到了!现在,为了匹配调用的更改语法,Objective-C 还更改了
multiplyFraction
定义的语法:但是您为
????
编写了什么。正如您将看到的语法仅命名第二个参数 (right
),而没有为第一个参数指定名称(left
)。 Objective-C隐藏这个参数的传递,每个方法都至少有一个参数 - 它是该方法发送到的“对象”(而不是“ADT”)。它需要一个名称,以便您可以引用它,该名称是self
:这本质上就是它 -
self
是第一个参数的名称。面向对象的语言建立在这个基础上,例如:
struct
的“字段”;@interface...
替换struct...
;并且不是在标头中的类型 (struct
) 之后列出方法(函数),而是在其内部列出(`@interface);但在底层,Objective-C 类被实现为 C
struct
...HTH
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:And you'd use it like:
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:
becomes:
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 bothhalf
andtwoThirds
.Almost there! Now to match the changed syntax for the call Objective-C also changes the syntax of the definition of
multiplyFraction
: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 wasleft
). 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 isself
:And this is essentially it -
self
is the name of the first argument.Object-oriented languages build upon this base, for example:
struct
;@interface...
replacesstruct...
; 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
Objective C 强调使用 getter 和 setter。为了让事情变得更简单,当你 @synthesize 某些东西时,它甚至会生成 getter 和 setter。
因此
访问 topSpeed 的 getter。如果省略“self”部分,则相当于直接访问实例变量(ivars)(不好的做法)。
之所以在变量名前加下划线,也是为了明确区分实例变量和实例变量的 getter。这样,我们就不会意外地在没有“self”的情况下引用topSpeed。
您需要在所有地方使用 self 访问变量,除了:
希望有帮助。
Objective C emphasizes using getters and setters. To make things simpler, it even generates getters and setters when you @synthesize something.
So
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.
self 确实是对运行代码的类实例的指针引用。在本例中,
self
将是对 Spaceship 类实例的引用。当您在类方法中引用 self(这是非常有可能且可接受的行为)时,您实际上是在引用代表该类的单例实例。您还可以通过调用
[Spaceship class]
来获取此单例实例。实际上,当您需要分配新实例时,您主要会在工厂方法中使用self
。您似乎更困惑的是有关其他类的语法。你问:
Wormhole *nearestWormhole
表示Wormhole
类的实例,名为nearestWormhole
。因此,当您使用 self.nearestWormhole 时,它是指向 Workhole 类实例的指针。在 Spaceship 类中,您实际上可以使用 _nearestWormhole 或 self.nearestWormhole 来访问该指针。其他类可能会调用诸如 spaceship.nearestWormhole 之类的东西,它正在使用访问器。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 useself
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:
Wormhole *nearestWormhole
represents an instance of theWormhole
class, namednearestWormhole
. So, when you useself.nearestWormhole
, that is a pointer to a instance of theWorkhole
class. Inside the Spaceship class you could actually use _nearestWormhole or self.nearestWormhole to access that pointer. Other classes might call something likespaceship.nearestWormhole
, which is using the accessor.“self”指的是当前类的实例,即在您的示例中它将指的是 Spaceship 类的实例。因为“self”始终引用类的实例,所以不可能在类方法中调用 self。
'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.