为什么是 [object doSomething] 而不是 [*object doSomething]? [英] Why [object doSomething] and not [*object doSomething]?

查看:29
本文介绍了为什么是 [object doSomething] 而不是 [*object doSomething]?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Objective-C中,为什么[object doSomething]?难道不是 [*object doSomething] 因为你在对象上调用一个方法吗?这意味着你应该取消引用指针吗?

In Objective-C, why [object doSomething]? Wouldn't it be [*object doSomething] since you're calling a method on the object?, which means you should dereference the pointer?

推荐答案

答案可以追溯到 Objective-C 的 C 根源.Objective-C 最初是作为 C 的编译器预处理器编写的.也就是说,Objective-C 并没有被编译那么多,而是被转换成直接的 C 然后编译.

The answer harkens back to the C roots of Objective-C. Objective-C was originally written as a compiler pre-processor for C. That is, Objective-C wasn't compiled so much as it was transformed into straight C and then compiled.

从类型id的定义开始.声明为:

Start with the definition of the type id. It is declared as:

typedef struct objc_object {
    Class isa;
} *id;

也就是说,id 是指向第一个字段类型为 Class 的结构的指针(它本身是指向定义类的结构的指针).现在,考虑 NSObject:

That is, an id is a pointer to a structure whose first field is of type Class (which, itself, is a pointer to a structure that defines a class). Now, consider NSObject:

@interface NSObject <NSObject> {
    Class   isa;
}

注意NSObject的布局和id指向的类型的布局是一样的.这是因为,实际上,Objective-C 对象的实例实际上只是一个指向结构的指针,该结构的第一个字段——始终是一个指针——指向包含该实例的方法的类(以及一些其他元数据)).

Note that the layout of NSObject and the layout of the type pointed to by id are identical. That is because, in reality, an instance of an Objective-C object is really just a pointer to a structure whose first field -- always a pointer -- points to the class that contains the methods for that instance (along with some other metadata).

当您继承 NSObject 并添加一些实例变量时,出于所有意图和目的,您只需创建一个新的 C 结构,该结构包含您的实例变量作为该结构中的插槽,并连接到所有超类的实例变量的插槽上.(现代运行时的工作方式略有不同,因此超类可以附加 ivars,而无需重新编译所有子类.

When you subclass NSObject and add some instance variables you are, for all intents and purposes, simply creating a new C structure that contains your instance variables as slots in that structure concatenated on the slots for the instance variables for all superclasses. (The modern runtime works slightly differently so that a superclass can have ivars appended without requiring all subclasses to be recompiled).

现在,考虑这两个变量之间的差异:

Now, consider the difference between these two variables:

NSRect foo;
NSRect *bar;

(NSRect 是一个简单的 C 结构——不涉及 ObjC).foo 是使用堆栈上的存储创建的.一旦堆栈帧关闭,它将无法生存,但您也不必释放任何内存.bar 是对 NSRect 结构的引用,该结构很可能是使用 malloc() 在堆上创建的.

(NSRect being a simple C structure -- no ObjC involved). foo is created with the storage on the stack. It will not survive once the stack frame is closed, but you also don't have to free any memory. bar is a reference to an NSRect structure that was, most likely, created on the heap using malloc().

如果你想说:

NSArray foo;
NSArray *bar;

编译器会抱怨第一个,说Objective-C 中不允许基于堆栈的对象.换句话说,所有Objective-C 对象必须从堆中分配(或多或少——有一两个例外,但它们对本次讨论来说相对深奥),因此,你总是通过该对象在堆上的地址来引用该对象;您总是使用指向对象的指针(而 id 类型实际上只是指向任何旧对象的指针).

The compiler will complain about the first, saying something along the lines of stack based objects are not allowed in Objective-C. In other words, all Objective-C objects must be allocated from the heap (more or less-- there are one or two exceptions, but they are comparatively esoteric to this discussion) and, as a result, you always refer to an object through the address of said object on the heap; you are always working with pointers to objects (and the id type really is just a pointer to any old object).

回到该语言的 C 预处理器根源,您可以将每个方法调用转换为 C 的等效行.例如,以下两行代码是相同的:

Getting back to the C preprocessor roots of the language, you can translate every method call to an equivalent line of C. For example, the following two lines of code are identical:

[myArray objectAtIndex: 42];
objc_msgSend(myArray, @selector(objectAtIndex:), 42);

同样,一个方法声明如下:

Similarly, a method declared like this:

- (id) objectAtIndex: (NSUInteger) a;

相当于这样声明的C函数:

Is equivalent to C function declared like this:

id object_at_index(id self, SEL _cmd, NSUInteger a);

并且,查看 objc_msgSend(),第一个参数被声明为 id 类型:

And, looking at objc_msgSend(), the first argument is declared to be of type id:

OBJC_EXPORT id objc_msgSend(id self, SEL op, ...);

这正是您不使用 *foo 作为方法调用目标的原因.通过上述形式进行转换——对 [myArray objectAtIndex: 42] 的调用被转换为上面的 C 函数调用,然后它必须调用具有等效 C 函数调用声明的东西(全部装扮成方法语法).

And that is exactly why you don't use *foo as the target of a method call. Do the translation through the above forms -- the call to [myArray objectAtIndex: 42] is translated to the above C function call which then must call something with the equivalent C function call declaration (all dressed up in method syntax).

对象引用被执行是因为它让信使 -- objc_msgSend() 访问类,然后找到方法实现 -- 以及该引用然后成为第一个参数 -- 方法的 self --最终执行.

The object reference is carried through because it gives the messenger -- objc_msgSend() access to the class to then find the method implementation -- as well as that reference then becoming the first parameter -- the self -- of the method that is eventually executed.

如果你真的想深入,从这里开始.但是不要打扰,直到你完全了解这个.

If you really want to go deep, start here. But don't bother until you have fully grokked this.

这篇关于为什么是 [object doSomething] 而不是 [*object doSomething]?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆