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)
既obj和str可浇铸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)
谢谢!
那么它的实例变量的实际值在哪里以及如何存储?
它们始终存放在同一个地方 - 在对象内部.如你所说,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对象,这几乎是一回事.
| 归档时间: |
|
| 查看次数: |
1145 次 |
| 最近记录: |