这是我参与更文挑战的第3天,活动详情查看: 更文挑战
前言
Objective-C
中对象是什么,是怎么实现的呢?众所周知,Objective-C
是有C++
演变而来的,那么不难猜测,实现的方法就只有两种C++
中的类class
或者结构体。接下来就使用clang
来看看Objective-C
中类怎么实现的。
OC对象的实现
为了更加方便,我新建了一个macos
的命令行项目,顺便把我的main.m
改成了main.mm
,可以对比C++
的类和Objective-C
的类。
main.mm
文件代码:
#import <Foundation/Foundation.h>
class LQPeople
{
private:
int a;
protected:
int b`;`
public:
int c;
};
@interface LQTest : NSObject
@property(nonatomic,copy)NSString *name;
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
NSLog(@"Hello, World!");
}
return 0;
}
复制代码
使用clang
命令
clang -rewrite-objc main.mm -o main.cpp
得到我们的mian.cpp
文件,打开cpp文件搜索我们的LQTest
。
发现LQTest
的确是两种猜想中的一种实现的,是由结构体实现的,不过隐隐约约感觉有些不对劲,我们的name
去哪了?原来是LQTest
没有被实现…
再来一次…
main.mm
文件代码:
#import <Foundation/Foundation.h>
class LQPeople
{
private:
int a;
protected:
int b;
public:
int c;
};
@interface LQTest : NSObject
@property(nonatomic,copy)NSString *name;
@end
@implementation LQTest
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
NSLog(@"Hello, World!");
}
return 0;
}
复制代码
使用clang命令
clang -rewrite-objc main.mm -o main.cpp
得到我们的mian.cpp文件,然后打开cpp查看。
这下就对了,我们的对象LQTest
变成了结构体,得出结论OC的对象就是struct实现的。
小结
- OC的对象就是struct实现的。
- OC的对象没有实现,只会生成一个类标识。
OC对象的本质
我们已经知道OC的对象是由结构体实现的,接下来继续探索,对象具体是怎么实现的?对象的本质是什么?属性会变成什么?方法又会变成什么?
属性
先上代码:
@interface LQTest : NSObject
@property(nonatomic,assign)int i;
@property(nonatomic,assign)char c;
@property(nonatomic,assign)bool b;
@property(nonatomic,strong)NSString *name;
@property(nonatomic,strong)NSData *data;
@property(nonatomic,strong)NSDate *date;
@end
@implementation LQTest
-(void)test {
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
NSLog(@"Hello, World!");
}
return 0;
}
复制代码
使用clang
命令
clang -rewrite-objc main.mm -o main.cpp
得到我们的mian.cpp
文件,然后打开查看。
LQTest
第一个是父类,NSObject_IMPL
,NSObject_IMPL
一个Class
类型的isa
,Class
是一个objc_class
类型的指针,当我想继续查找objc_class
时却只找到了一个定义,具体实现应该不在这里,这个暂时不深究。这个isa
应该就是我们常用地self
了。
struct NSObject_IMPL {
Class isa;
};
typedef struct objc_class *Class;
复制代码
接下来查看定义的基础成员变量还保持着char
、bool
、int
。但是NSString
、NSData
和NSDate
却不是我们OC中的NSString
、NSData
和NSDate
了。都是结构体objc_object
了。objc_object
这里也只看到一里面一个Class
类型的isa
指针,这里就不深究了。
// @class NSString;
#ifndef _REWRITER_typedef_NSString
#define _REWRITER_typedef_NSString
typedef struct objc_object NSString;
typedef struct {} _objc_exc_NSString;
#endif
// @class NSData;
#ifndef _REWRITER_typedef_NSData
#define _REWRITER_typedef_NSData
typedef struct objc_object NSData;
typedef struct {} _objc_exc_NSData;
#endif
// @class NSDate;
#ifndef _REWRITER_typedef_NSDate
#define _REWRITER_typedef_NSDate
typedef struct objc_object NSDate;
typedef struct {} _objc_exc_NSDate;
#endif
struct objc_object {
Class _Nonnull isa __attribute__((deprecated));
};
复制代码
方法
在结构体这块定义里面我们并没有看到我们定义的方法。定义的方法去哪里了?我们继续查找。
static struct /*_method_list_t*/ {
unsigned int entsize; // sizeof(struct _objc_method)
unsigned int method_count;
struct _objc_method method_list[25];
} _OBJC_$_INSTANCE_METHODS_LQTest __attribute__ ((used, section ("__DATA,__objc_const"))) = {
sizeof(_objc_method),
25,
{{(struct objc_selector *)"test", "v16@0:8", (void *)_I_LQTest_test},
{(struct objc_selector *)"i", "i16@0:8", (void *)_I_LQTest_i},
{(struct objc_selector *)"setI:", "v20@0:8i16", (void *)_I_LQTest_setI_},
{(struct objc_selector *)"c", "c16@0:8", (void *)_I_LQTest_c},
{(struct objc_selector *)"setC:", "v20@0:8c16", (void *)_I_LQTest_setC_},
{(struct objc_selector *)"b", "B16@0:8", (void *)_I_LQTest_b},
{(struct objc_selector *)"setB:", "v20@0:8B16", (void *)_I_LQTest_setB_},
{(struct objc_selector *)"name", "@16@0:8", (void *)_I_LQTest_name},
{(struct objc_selector *)"setName:", "v24@0:8@16", (void *)_I_LQTest_setName_},
{(struct objc_selector *)"data", "@16@0:8", (void *)_I_LQTest_data},
{(struct objc_selector *)"setData:", "v24@0:8@16", (void *)_I_LQTest_setData_},
{(struct objc_selector *)"date", "@16@0:8", (void *)_I_LQTest_date},
{(struct objc_selector *)"setDate:", "v24@0:8@16", (void *)_I_LQTest_setDate_},
{(struct objc_selector *)"i", "i16@0:8", (void *)_I_LQTest_i},
{(struct objc_selector *)"setI:", "v20@0:8i16", (void *)_I_LQTest_setI_},
{(struct objc_selector *)"c", "c16@0:8", (void *)_I_LQTest_c},
{(struct objc_selector *)"setC:", "v20@0:8c16", (void *)_I_LQTest_setC_},
{(struct objc_selector *)"b", "B16@0:8", (void *)_I_LQTest_b},
{(struct objc_selector *)"setB:", "v20@0:8B16", (void *)_I_LQTest_setB_},
{(struct objc_selector *)"name", "@16@0:8", (void *)_I_LQTest_name},
{(struct objc_selector *)"setName:", "v24@0:8@16", (void *)_I_LQTest_setName_},
{(struct objc_selector *)"data", "@16@0:8", (void *)_I_LQTest_data},
{(struct objc_selector *)"setData:", "v24@0:8@16", (void *)_I_LQTest_setData_},
{(struct objc_selector *)"date", "@16@0:8", (void *)_I_LQTest_date},
{(struct objc_selector *)"setDate:", "v24@0:8@16", (void *)_I_LQTest_setDate_}}
};
// @implementation LQTest
static void _I_LQTest_test(LQTest * self, SEL _cmd) {
}
static int _I_LQTest_i(LQTest * self, SEL _cmd) { return (*(int *)((char *)self + OBJC_IVAR_$_LQTest$_i)); }
static void _I_LQTest_setI_(LQTest * self, SEL _cmd, int i) { (*(int *)((char *)self + OBJC_IVAR_$_LQTest$_i)) = i; }
static char _I_LQTest_c(LQTest * self, SEL _cmd) { return (*(char *)((char *)self + OBJC_IVAR_$_LQTest$_c)); }
static void _I_LQTest_setC_(LQTest * self, SEL _cmd, char c) { (*(char *)((char *)self + OBJC_IVAR_$_LQTest$_c)) = c; }
static bool _I_LQTest_b(LQTest * self, SEL _cmd) { return (*(bool *)((char *)self + OBJC_IVAR_$_LQTest$_b)); }
static void _I_LQTest_setB_(LQTest * self, SEL _cmd, bool b) { (*(bool *)((char *)self + OBJC_IVAR_$_LQTest$_b)) = b; }
static NSString * _I_LQTest_name(LQTest * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_LQTest$_name)); }
static void _I_LQTest_setName_(LQTest * self, SEL _cmd, NSString *name) { (*(NSString **)((char *)self + OBJC_IVAR_$_LQTest$_name)) = name; }
static NSData * _I_LQTest_data(LQTest * self, SEL _cmd) { return (*(NSData **)((char *)self + OBJC_IVAR_$_LQTest$_data)); }
static void _I_LQTest_setData_(LQTest * self, SEL _cmd, NSData *data) { (*(NSData **)((char *)self + OBJC_IVAR_$_LQTest$_data)) = data; }
static NSDate * _I_LQTest_date(LQTest * self, SEL _cmd) { return (*(NSDate **)((char *)self + OBJC_IVAR_$_LQTest$_date)); }
static void _I_LQTest_setDate_(LQTest * self, SEL _cmd, NSDate *date) { (*(NSDate **)((char *)self + OBJC_IVAR_$_LQTest$_date)) = date; }
// @end
复制代码
我们可以看到我们的方法已经全部变成了c++
的静态函数了,有一个_method_list_t
来映射他们。
总结
- OC对象是由结构体实现的。
- OC对象的基础成员变量还保留为基础成员变量,但是类类型的成员变量都转变成结构体指针了。
- OC对象的类方法都是有静态函数实现,再用
method_list
映射。