Runtime

 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,即NSObjectmeta-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));  //打印当前调用的方法名

发布了84 篇原创文章 · 获赞 23 · 访问量 10万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章