- instance-对象
创建两个对象,并打印,
例一:
//instance-对象
NSObject *obj1 = [NSObject new];
NSObject *obj2 = [NSObject new];
可以看到两个对象的内存地址不一样
2020-05-05 14:26:35.340051+0800 class对象[31421:2142371] 0x6000030e80f0 0x6000030e80d0
结论:因为创建的对象可以有多个,如果对象里面有属性,不同的对象可以给相同的属性设置不同的值,比如一个MJPerson 有一个 age属性,我可以创建一个MJPerson 设置age值为18,同样创建一个MJPerson,age设置为20,
- class-类对象
打印第一个例子中对象的类对象地址,
注意:对象想要调用方法,必须通过isa指针找到类对象,从类对象里面寻找方法,因为对象里面只存储了成员变量,并没有方法,方法都存在类对象里面,而类方法存在元类对象里面,转成消息发送就是:
objc_msgSend(person,@selector(instanceMethod));调用对象方法
objc_msgSend([person class],@selector(classMethod));调用类方法
例二:
//class-类对象
Class objClass1 = [obj1 class];
Class objClass2 = [obj2 class];
Class objClass3 = [NSObject class];
Class objClass4 = object_getClass(obj1);
Class objClass5 = object_getClass(obj2);
打印结果如下: 可以看到对象的类对象内存地址一毛一样,证明,同一个类创建的多个对象,它的类对象只有一个-----为什么???
原因:不管你创建多少对象,它的方法都是一样的,所有没有必要生成N多个类对象,只需要一份类对象,保存它所有的方法
2020-05-05 14:26:35.339948+0800 class对象[31421:2142371] 0x7fff89be1d00 0x7fff89be1d00 0x7fff89be1d00 0x7fff89be1d00 0x7fff89be1d00
- metaClass-元类对象
既然有了类对象,为什么还需要元类对象?
注意:下面打印的objMetaClass3
和objMetaClass3
都不是元类对象,objc_getClass()
这个方法只能得到类对象,原因可以看我的上一篇文章:传送门
例三:
//metaclass-元类对象
Class objMetaClass1 = objc_getMetaClass("NSObject");
Class objMetaClass2 = object_getClass(objClass4);
Class objMetaClass3 = objc_getClass("NSObject");
Class objMetaClass4 = [[[NSObject class]class]class];
打印结果如下:
2020-05-05 14:26:35.339815+0800 class对象[31421:2142371] 0x7fff89be1cd8 0x7fff89be1cd8 0x7fff89be1d00 0x7fff89be1d00
类对象的地址 和元类对象的地址又不同,我们知道-->
一个类包含有几个大块:
--成员变量数组
--协议数组
--类方法数组
--对象方法数组
--分类数组
--局部变量数组
附送一个编译命令行:
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc MJPerson.m -o MJPerson.cpp
xcrun :x->Xcode
xcrun -sdk iphoneos :指派Xcode生成 iphoneos 系统的文件
clang : Mac自带的编译器
clang -arch arm64 :指定架构类型为arm64,这是64位的,iPhone 还有armv7,armv7s,armv6,这几个都是32位的,还有i386,这个针对模拟器的,
-rewrite-objc MJPerson.m -o MJPerson.cpp : 重写 MJPerson.m 文件 输出成MJPerson.cpp
struct _prop_t {
const char *name;
const char *attributes;
};
struct _protocol_t;
struct _objc_method {
struct objc_selector * _cmd;
const char *method_type;
void *_imp;
};
struct _protocol_t {
void * isa; // NULL
const char *protocol_name;
const struct _protocol_list_t * protocol_list; // super protocols
const struct method_list_t *instance_methods;
const struct method_list_t *class_methods;
const struct method_list_t *optionalInstanceMethods;
const struct method_list_t *optionalClassMethods;
const struct _prop_list_t * properties;
const unsigned int size; // sizeof(struct _protocol_t)
const unsigned int flags; // = 0
const char ** extendedMethodTypes;
};
struct _ivar_t {
unsigned long int *offset; // pointer to ivar offset location
const char *name;
const char *type;
unsigned int alignment;
unsigned int size;
};
struct _class_ro_t {
unsigned int flags;
unsigned int instanceStart;
unsigned int instanceSize;
const unsigned char *ivarLayout;
const char *name;
const struct _method_list_t *baseMethods;
const struct _objc_protocol_list *baseProtocols;
const struct _ivar_list_t *ivars;
const unsigned char *weakIvarLayout;
const struct _prop_list_t *properties;
};
struct _class_t {
struct _class_t *isa;
struct _class_t *superclass;
void *cache;
void *vtable;
struct _class_ro_t *ro;
};
struct _category_t {
const char *name;
struct _class_t *cls;
const struct _method_list_t *instance_methods;
const struct _method_list_t *class_methods;
const struct _protocol_list_t *protocols;
const struct _prop_list_t *properties;
};
类 和 元类 的区别就在于,元类(metaClass)当中存放了类方法,而类(Class)中存放类方法的数组为空,怎么验证???
- 创建一个类 包含类方法 和对象方法, 打印类的所有方法 和元类的所有方法,以MJPerson为例
例四:
@interface MJPerson : NSObject
@property (nonatomic,strong)NSString *mj_person;
- (void)testInstanceClass;
+ (void)testMetaClass;
@end
这个是打印类所有的方法的函数,使用时需要导入#import
文件
void DumpObjcMethods(Class clz)
{
unsigned int methodCount = 0;
Method *methods = class_copyMethodList(clz, &methodCount);
printf("Found %d methods on '%s'\n", methodCount, class_getName(clz));
for (unsigned int i = 0; i < methodCount; i++)
{
Method method = methods[i];
printf("\t'%s' has method named '%s' of encoding '%s'\n",
class_getName(clz),
sel_getName(method_getName(method)),
method_getTypeEncoding(method));
/**
* Or do whatever you need here...
*/
}
free(methods);
}
例五:创建MJPerson类,打印它的所有方法
MJPerson *person1 = [MJPerson new];//instance-对象
Class personCls = object_getClass(person1);//class-类对象
Class personMetaCls = object_getClass(personCls);//metaclass-元类对象
BOOL isMetaCls = class_isMetaClass(personMetaCls);
DumpObjcMethods(personCls);
DumpObjcMethods(personMetaCls);
NSLog(@"%p %p %p %d %@",
person1,
personCls,
personMetaCls,
isMetaCls,
personMetaCls
);
结果如下:
Found 4 methods on 'MJPerson'
'MJPerson' has method named 'testInstanceClass' of encoding 'v16@0:8'
'MJPerson' has method named 'mj_person' of encoding '@16@0:8'
'MJPerson' has method named 'setMj_person:' of encoding 'v24@0:8@16'
'MJPerson' has method named '.cxx_destruct' of encoding 'v16@0:8'
Found 1 methods on 'MJPerson'
'MJPerson' has method named 'testMetaClass' of encoding 'v16@0:8'
2020-05-05 15:04:37.639828+0800 class对象[32370:2166200] 0x600001bf03f0 0x10d430618 0x10d4305f0 1 MJPerson
根据结果可以看到,类方法有四个
一个testInstanceClass实例方法,
一个set,get方法,
一个cxx_destruct--析构函数
而元类对象只有一个方法 testMetaClass
- 如果 MJPerson有一个类方法
+(void)test
,有一个分类(Category)继承自NSObject,它里面有个-(void)test
方法,[MJPerson test]
会不会报错???
@interface NSObject (Test)
- (void)test;
@end
@implementation NSObject (Test)
- (void)test{
NSLog(@"%s",__func__);
}
@end
@interface MJPerson : NSObject
+ (void)test;
@end
@implementation MJPerson
@end
这么调用:
[MJPerson test];
答案是不会报错,打印结果如下;
2020-05-05 18:36:13.224881+0800 class对象[37802:2256463] -[NSObject(Test) test]
原因:以本文为例,NSObject的元类superclass指针最后指向它自己的类对象,所以当类方法寻找不到的时候,NSObject的元类,就会到他类对象里面寻找,所以最终会调用到-(void)test
对象方法,而不是报方法找不到的错误.
对应的就是图中这根线: