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

查看:72
本文介绍了为什么[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 中不允许使用基于 stack的对象.换句话说,必须从堆中分配 all 个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).

之所以会执行对象引用,是因为它使Messenger-objc_msgSend()可以访问该类,然后找到方法实现-以及该引用随后成为该方法的第一个参数-自身-最终执行.

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天全站免登陆