这是我参与更文挑战的第3天,活动详情查看: 更文挑战
前言
首先讲讲类和对象的关系,类(class)和对象(object)是两种以计算机为载体的计算机语言的合称。对象是对客观事物的抽象,类是对对象的抽象。类是一种抽象的数据类型。简单的说就是类是定义好的类型,对象就是我们new或者alloc&init的出来的。那么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时却只找到了一个定义,具体实现应该不在这里,这个暂时不深究,之后在研究。
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来映射他们。