typedef struct objc_class *Class; //类在Objective-C中就是结构体指针
struct objc_class {
Class _Nonnull isa OBJC_ISA_AVAILABILITY; //isa 指向元类的objc_class结构体指针,iOS中的类也是对象,元类中储存有类对象的类方法
#if !__OBJC2__
Class _Nullable super_class OBJC2_UNAVAILABLE; //指向父类的objc_class结构体指针,可以通过父类的指针找到变量和方法
const char * _Nonnull name OBJC2_UNAVAILABLE; //类名
long version OBJC2_UNAVAILABLE; //版本号,默认为0
long info OBJC2_UNAVAILABLE; //其他信息,运行期间的一些位标示
long instance_size OBJC2_UNAVAILABLE; //类实例变量大小
struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE; //该类的成员变量链表,是objc_ivar_list结构体指针
struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE; //方法链表结构体
struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE; //对象使用过的方法链表
struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE; //协议链表
#endif
} OBJC2_UNAVAILABLE;
/* Use `Class` instead of `struct objc_class *` */
其中!__OBJC2__表示非Objective-C 2.0的版本,Objective-C是从1.0发展到现在的2.0,这个声明是为了兼容1.0的Objective-C,若是Objective-C 2.0的话,可见objc_class与objc_object的定义是一样的,都是只有一个isa指针,所以说在Objective-C里面,类也是一个对象
struct objc_ivar_list {
int ivar_count OBJC2_UNAVAILABLE;
/* variable length structure */
struct objc_ivar ivar_list[1] OBJC2_UNAVAILABLE;
} OBJC2_UNAVAILABLE;
//objc_ivar 变量结构体---名称,类型,偏移字节和占用的空间
struct objc_ivar {
char * _Nullable ivar_name OBJC2_UNAVAILABLE;
char * _Nullable ivar_type OBJC2_UNAVAILABLE;
int ivar_offset OBJC2_UNAVAILABLE;
#ifdef __LP64__
int space OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;
struct objc_method_list {
struct objc_method_list * _Nullable obsolete OBJC2_UNAVAILABLE;
int method_count OBJC2_UNAVAILABLE;
#ifdef __LP64__
int space OBJC2_UNAVAILABLE;
#endif
/* variable length structure */
struct objc_method method_list[1] OBJC2_UNAVAILABLE;
} OBJC2_UNAVAILABLE;
//objc_method //对象的每个方法的结构体,SEL是方法选择器,是HASH后的值,可以通过这个值找到函数体的实现,IMP 是函数指针
struct objc_cache {
unsigned int mask /* total = mask + 1 */ OBJC2_UNAVAILABLE;
unsigned int occupied OBJC2_UNAVAILABLE;
Method _Nullable buckets[1] OBJC2_UNAVAILABLE;
};
struct objc_protocol_list {
struct objc_protocol_list * _Nullable next;
long count;
__unsafe_unretained Protocol * _Nullable list[1];
};
实线是super_class 指针,虚线是isa指针。根元类的超类NSObject,而isa 指向了自己。NSObject的超类为nil,也就是它没有超类。
类的实例对象的isa 指向它的类,类的 isa 指向该类的 metaclass
类的super_class 指向其父类,如果该类为根类则值为NULL
metaclass的 isa 指向根 metaclass,如果该 metaclass 是根 metaclass 则指向自身。
metaclass的 super_class 指向父 metaclass,如果该 metaclass 是根 metaclass 则指向该 metaclass 对应的类。
Object-C为每个类的定义生成两个objc_class,一个普通的class,另一个即metaclass.可以在运行期创建这两个objc_class数据结构,然后使用objc_addClass将 class 注册到运行时系统中,以实现动态创建一个新类。
class 实例对象的isa 指向的结构体
metaclass class 的 isa 指向的一个结构体
动态创建类和对象:
动态创建类:
1、为"classpair" 分配空间 创建一个新类和元类
//如果要创建一个根类,则superclass 指定为Nil
//extraBytes:通常指定为0,该参数是分配给类和元类对象尾部的索引ivars的字节数
objc_allocateClassPair(Class superclass, const char *name, size_t extraBytes)
2、为创建的类添加方法和成员变量
//实例方法和实例变量应该提添加到类自身上,而类方法应该添加到类的元类上
//向类中添加一个方法 cls: 目标类 name:新方法 imp:函数的地址
class_addMethod(Class cls, SEL name, IMP imp, const char *types)
//向类中添加一个实例变量
class_addIvar(Class cls, const char * name, size_t size, uint8_talignment, const char * types)
3、注册创建的类,使其可用
//注册这个类
objc_registerClassPair(Class cls)
//这个例子是在运行时创建一个NSError 的子类RuntimeErrorSubclass,然后为这个类添加一个方法reportFunction,这个方法的实现是ReportFunction
Class newClass = objc_allocateClassPair([NSError class], "RuntimeErrorSubclass", 0);
class_addMethod(newClass,@selector(reportFunction), (IMP)ReportFunction, "v@:");
objc_registerClassPair(newClass);
id c = [[newClass alloc] init];
[c performSelector:@selector(reportFunction) withObject:nil];
void ReportFunction(id self,SEL _cmd){
NSLog(@"This object is%p",self);
NSLog(@"Class is %@,andsuper is %@",[self class],[self superclass]);
Class currentClass = [self class];
for (int i = 0; i < 4; i ++) {
NSLog(@"Following theisa pointer %d times gives %p",i,currentClass);
currentClass = object_getClass(currentClass);
}
NSLog(@"NSObject's classis %p", [NSObjectclass]);
NSLog(@"NSObject's metaclass is %p",object_getClass([NSObject class]));
}
//运行后打印结果为:
[64427:18295107] This object is 0x6040004438a0
[64427:18295107] Class is RuntimeErrorSubclass,andsuper is NSError
[64427:18295107] Following the isa pointer 0 timesgives 0x60400025cb30
[64427:18295107] Following the isa pointer 1 timesgives 0x60400025c2f0
[64427:18295107] Following the isa pointer 2 timesgives 0x111511e58
[64427:18295107] Following the isa pointer 3 timesgives 0x111511e58
[64427:18295107] NSObject's class is 0x111511ea8
[64427:18295107] NSObject's meta class is0x111511e58
在for循环中,通过objc_getClass 来获取对象的isa,并将其打印出来,依次可以回溯到NSObject 的meta-calss。
分析结果可以看到最后指针指向的地址是0x0,即NSObject的meta-class的类地址。
动态创建对象:
1、动态为一个类添加方法:
手动创建一个Dog类,在viewDidLoad方法中写上以下代码:
//performSelector: 动态添加方法
Dog *dog = [[Dog alloc] init];
// [dog performSelector:@selector(eat)]; //不带参数的方法
[dog performSelector:@selector(eat:) withObject:@123]; //带参数的方法
然后创建一个在Dog类的.m文件中进行动态添加方法:#import "Dog.h"
#import <objc/message.h>
@implementation Dog
//定义一个函数
//默认一个方法都有两个参数:self,_cmd 是隐式参数
//self: 方法的调用者 _cmd : 调用方法的编号 再增加参数直接往后添加例如:id param
void test(id self, SEL _cmd,id param){
NSLog(@"调用了test %@ -- %@ -- %@ ",self,NSStringFromSelector(_cmd),param); //不带参数的打印结果:调用了test <Dog: 0x7f88e4836b70> -- eat
}
//带有参数的打印结果: 调用了test <Dog: 0x7f8e8ad7a680> -- eat: -- 123
//动态添加方法,首先要实现resolveInstanceMethod
//resolveInstanceMethod调用: 当调用没有实现的方法时就会调用resolveInstanceMethod这个方法
//resolveInstanceMethod作用: 知道哪些方法没有实现,从而动态添加方法
//sel : 获取到没有实现的方法 NSLog(@"%@",NSStringFromSelector(sel)); // 打印结果:"eat"
+ (BOOL)resolveInstanceMethod:(SEL)sel {
//动态添加eat方法
if (sel == @selector(eat:)) {
/*
__unsafe_unretained Class cls: 给哪个类添加方法
SEL name : 添加方法的方法编号是什么
IMP imp:方法实现,函数的入口,函数名
const char *types: 方法的类型
*/
class_addMethod(self, sel, (IMP)test, "v@:@"); //v :返回值 void @ : 参数id : :是SEL
}
return [super resolveInstanceMethod:sel];
}
关于方法的类型的所有的情况如下:
/*
c<span style="white-space:pre"> </span>A char
i<span style="white-space:pre"> </span>An int
s<span style="white-space:pre"> </span>A short
l<span style="white-space:pre"> </span>A long
<span style="white-space:pre"> </span>l is treated as a 32-bit quantity on 64-bit programs.
q<span style="white-space:pre"> </span>A long long
C<span style="white-space:pre"> </span>An unsigned char
I<span style="white-space:pre"> </span>An unsigned int
S<span style="white-space:pre"> </span>An unsigned short
L<span style="white-space:pre"> </span>An unsigned long
Q<span style="white-space:pre"> </span>An unsigned long long
f<span style="white-space:pre"> </span>A float
d<span style="white-space:pre"> </span>A double
B<span style="white-space:pre"> </span>A C++ bool or a C99 _Bool
v<span style="white-space:pre"> </span>A void
*<span style="white-space:pre"> </span>A character string (char *)
@<span style="white-space:pre"> </span>An object (whether statically typed or typed id)
#<span style="white-space:pre"> </span>A class object (Class)
:<span style="white-space:pre"> </span>A method selector (SEL)
[array type]<span style="white-space:pre"> </span>An array
{name=type...}<span style="white-space:pre"> </span>A structure
(name=type...)<span style="white-space:pre"> </span>A union
bnum<span style="white-space:pre"> </span>A bit field of num bits
^type<span style="white-space:pre"> </span>A pointer to type
?<span style="white-space:pre"> </span>An unknown type (among other things, this code is used for function pointers)
*/
2、分类添加属性
尝试给NSObject 添加一个属性,在ViewDidLoad中调用:
NSObject *objc = [[NSObject alloc] init];
objc.name = @"hehe";
NSLog(@" -- %@",objc.name); //打印结果: -- hehe
为NSObject添加一个分类如下:@interface NSObject (Objc)
@property (nonatomic,copy) NSString *name;
@end
#import "NSObject+Objc.h"
#import <objc/message.h>
@implementation NSObject (Objc)
- (void)setName:(NSString *)name {
//添加属性,一般都是相对于对象而言的,给某一个对象添加属性就是给某个对象产生关联
/*
id object : 给哪个对象添加属性
const void *key : 属性名,根据key去获取关联的对象
id value :关联的值
objc_AssociationPolicy policy : 策略
*/
objc_setAssociatedObject(self, @"name", name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSString *)name {
return objc_getAssociatedObject(self, @"name");
}
_cmd:
在OC 中表示当前selector,正如self表示当前方法调用的实例对象
NSLog(@"%@",NSStringFromSelector(_cmd)); //打印当前调用的方法名