objective-c对象是否都是相同类型的C结构?

Tak*_*ano 4 runtime objective-c

我想知道语言的面向对象特性是如何在C中实现的.

如定义中<objc/runtime.h>,idtype是指向a的指针objc_object,objc_objecttype是C结构,只有一个成员isa存储a Class.那么存储任何对象的实例变量的实际值的位置和方式是什么?

还有一件事,所有Objective-C对象指针都可以被转换为id(这是一个指向C结构的指针,其中不存在继承等特性),Objective-C类只是编译器的限定符,并且所有实例同样类型objc_object

添加:

NSObject *obj = [NSObject new];
objc_object *objStruct = (__bridge objc_object *)obj;
NSLog(@"obj: %@", NSStringFromClass(objStruct->isa));

NSString *str = [NSString new];
objc_object *strStruct = (__bridge objc_object *)str;
NSLog(@"str: %@", NSStringFromClass(strStruct->isa));
Run Code Online (Sandbox Code Playgroud)

此代码编译并输出:

obj: NSObject, str: __NSCFConstantString
Run Code Online (Sandbox Code Playgroud)

objstr可浇铸objc_object *的,这意味着这两个变量是相同类型的指针,没有?

解决

明白!我误解了指针投射是如何工作的.obj并且str是不同结构类型的指针,但两者通常isa在内存前面都有类型成员,因此可以视为一个objc_object.下面的代码模仿了这个机制:

typedef struct {
    int isa;
} Fake_NSObject;

typedef struct {
    int isa;
    char *string;
} Fake_NSString;

Fake_NSObject obj = {1};
Fake_NSObject *objPtr = &obj;
NSLog(@"obj: %d", objPtr->isa); // prints 1

Fake_NSString str = {2, "abc"};
Fake_NSString *strPtr = &str;
NSLog(@"str: %d", strPtr->isa); // prints 2

Fake_NSObject *objPtr2 = (Fake_NSObject *)strPtr; // this is ok.
NSLog(@"obj2: %d", objPtr2->isa); // prints 2

Fake_NSString *strPtr2 = (Fake_NSString *)objPtr; // this is invalid, but still works.
NSLog(@"str2: %d", strPtr2->isa); // prints 1
Run Code Online (Sandbox Code Playgroud)

谢谢!

Cal*_*leb 5

那么它的实例变量的实际值在哪里以及如何存储?

它们始终存放在同一个地方 - 在对象内部.如你所说,id代表一个指向任何类型对象的指针.但是,除此之外,它没有定义任何特定类型 - 它没有说明对象的实际类型.

objc_object只是一种相当于的基本类型NSObject.看看NSObject.h,你会看到一个实例NSObject有一个实例变量,isa指针.对于NSProxyObjective-C中的另一个根类也是如此.子类NSObject或者NSProxy可以添加自己的实例变量,这些变量附加到父结构中.

如果所有Objective-C对象指针都可以转换为id,那么所有Objective-C类都只是编译器的限定符,并且在运行时所有这些实例都是objc_object的类型吗?

我不确定你在这里问什么.编译器不会阻止你向任何对象发送任何消息(虽然如果它认为你正在向不支持它的对象发送消息它会发出警告),所以在某种意义上编译器并不关心关于各种对象类型.另一方面,不同类型的对象不同的 - 没有所有类转换为的通用类型.

id非常类似于void *.void *是一个通用指针,你可以转换任何指针void *,但这并不意味着所有指针都是等价的.id添加限制是指为类型变量指定的指针id必须指向Objective-C对象,这几乎是一回事.

  • @TaketoSano你好像喝了太多C++.C根本没有类型安全性.** - "obj和str都可以转换为指向objc_object的指针,这意味着两个变量都是同一类型的指针,没有?" - 不.在C中,几乎任何东西都可以投射到任何东西.考虑`float pi = 3.14; uint32_t i =*(uint32_t*)&pi; id bogusPtr =(id)i;` (3认同)
  • @TaketoSano它们可以像我可以将任何给定对象转换为`void*`或`uintptr_t`并返回一样.强制转换是对编译器的承诺,如果您决定从该类型中"切掉"信息,那就是您的问题 (2认同)