美文网首页runtime相关RuntimeiOS学习记录
Objective-C Runtime 学习笔记之Objecti

Objective-C Runtime 学习笔记之Objecti

作者: 我系哆啦 | 来源:发表于2016-06-05 21:30 被阅读187次

    什么是Runtime

    Objective-C语言是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了运行时来处理。这种动态语言的优势在于:我们写代码时更具灵活性,如我们可以把消息转发给我们想要的对象,或者随意交换一个方法的实现等.
    我们将C++和Objective进行对比,虽然C++和Objective-C都是在C的基础上加入面向对象的特性扩充而成的程序设计语言,但二者实现的机制差异很大。C++是基于静态类型,而Objective-C是基于动态运行时类型。也就是说用C++编写的程序编译时就直接编译成了可令机器读懂的机器语言;用Objective-C编写的程序不能直接编译成可令机器读懂的机器语言,而是在程序运行的时候,通过Runtime把程序转为可令机器读懂的机器语言。Runtime是Objective不可缺少的重要一部分。
    **传送门->runtime源码

    类和对象

    <pre>
    /// An opaque type that represents an Objective-C class.
    typedef struct objc_class Class;
    typedef struct objc_object id;
    /// Represents an instance of a class.

    struct objc_class {
    Class isa OBJC_ISA_AVAILABILITY;

    if !OBJC2

    Class super_class                                        OBJC2_UNAVAILABLE;
    const char *name                                         OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;
    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache *cache                                 OBJC2_UNAVAILABLE;
    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;
    

    endif

    } OBJC2_UNAVAILABLE;

    struct objc_object {
    Class isa OBJC_ISA_AVAILABILITY;
    };
    </pre>

    • Class是一个指向objc_class结构体的指针,而id是一个指向objc_object结构体的指针,其中的isa是一个指向objc_class结构体的指针。其中的id就是我们所说的对象,Class就是我们所说的类。
    • 类与对象的区别就是类比对象多了很多特征成员,方法列表,父类,缓存,协议等信息。
    • isa:objc_object(实例对象)中isa指针指向的类结构称为class(也就是该对象所属的类),其中存放着普通成员变量与动态方法(“-”开头的方法);类对象中isa指针指向的类结构称为metaclass,其中存放着static类型的成员变量与static类型的方法(“+”开头的方法)。
    • super_class: 指向该类的父类的指针,如果该类是根类(如NSObject或NSProxy),那么super_class就为nil。
    • 类与对象的继承层次关系如下图所示,非常经典的一张图


      类与对象的继承层次关系图

    成员变量和属性

    • 定义

    <pre>
    //成员变量 Ivar

    • typedef struct objc_ivar *Ivar;
      objc_ivar的定义如下:
      struct objc_ivar {
      char *ivar_name OBJC2_UNAVAILABLE; // 变量名
      char *ivar_type OBJC2_UNAVAILABLE; // 变量类型
      int ivar_offset OBJC2_UNAVAILABLE; // �基地址偏移字节

    ifdef LP64

    int space OBJC2_UNAVAILABLE; // 占用空间

    endif

    }
    </pre>

    <pre>
    typedef struct objc_property *objc_property_t;
    typedef struct {
    const char *name; // 名称
    const char *value; // 值(通常是空的)
    } objc_property_attribute_t;
    </pre>

    • 常用方法

    <pre>
    // 获取类中指定名称实例成员变量的信息
    Ivar class_getInstanceVariable ( Class cls, const char *name );
    // 获取类成员变量的信息
    Ivar class_getClassVariable ( Class cls, const char *name );
    // 添加成员变量
    BOOL class_addIvar ( Class cls, const char *name, size_t size, uint8_t alignment, const char *types );
    // 获取整个成员变量列表
    Ivar * class_copyIvarList ( Class cls, unsigned int *outCount );
    </pre>

    <pre>
    // 获取指定的属性
    objc_property_t class_getProperty ( Class cls, const char *name );
    // 获取属性列表
    objc_property_t * class_copyPropertyList ( Class cls, unsigned int *outCount );
    // 为类添加属性
    BOOL class_addProperty ( Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount );
    // 替换类的属性
    void class_replaceProperty ( Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount );
    </pre>

    方法(SEL,IMP,METHOD)

    • Method代表类中的某个方法的类型
      <pre>
      typedef struct objc_method *Method;
      struct objc_method {
      SEL method_name OBJC2_UNAVAILABLE; // 方法名
      char *method_types OBJC2_UNAVAILABLE; // 方法类型
      IMP method_imp OBJC2_UNAVAILABLE; // 方法实现
      }
      </pre>

    • Sel 代表方法名
      <pre>
      typedef struct objc_selector *SEL;
      struct objc_selector {
      *name; OBJC2_UNAVAILABLE;// 名称
      char *types; OBJC2_UNAVAILABLE;// 类型
      };
      </pre>

    • IMP 表示方法实现,实际是一个函数指针
      <pre>
      typedef id (*IMP)(id, SEL, ...);
      </pre>

    • 常用方法
      <pre>
      // 添加类方法
      BOOL class_addMethod ( Class cls, SEL name, IMP imp, const char *types );
      // 获取实例方法
      Method class_getInstanceMethod ( Class cls, SEL name );
      // 获取类方法
      Method class_getClassMethod ( Class cls, SEL name );
      // 获取所有方法的数组
      Method * class_copyMethodList ( Class cls, unsigned int *outCount );
      // 替代方法的实现
      IMP class_replaceMethod ( Class cls, SEL name, IMP imp, const char *types );
      // 返回方法的具体实现
      IMP class_getMethodImplementation ( Class cls, SEL name );
      IMP class_getMethodImplementation_stret ( Class cls, SEL name );
      // 类实例是否响应指定的selector
      BOOL class_respondsToSelector ( Class cls, SEL sel );
      </pre>

    除了以上类型外,还有objc_protocol_list,cache,version等
    上面基本介绍了runtime中类和对象的基本知识,为了加深印象,这里做一个例子,手动创建一个类,添加方法并直接调用,遍历其中的成员变量和属性

    runtime实践

    <pre>
    /**

    • 创建一个方法,并用两种方法获取成员变量的值
    • @param self <#self description#>
    • @param _cmd <#_cmd description#>
    • @param text <#text description#>
      */
      void sayHelloFunction(id self,SEL _cmd,id text)
      {
      NSLog(@"%@个轮子的%@%@",object_getIvar(self, class_getInstanceVariable([self class], "_num")),[self valueForKey:@"_name"],text);
      }

    void test_runtime_class()
    {
    //动态创建一个继承自NSObject的Car类
    Class Car = objc_allocateClassPair([NSObject class], "Car", 0);

    //动态添加一个NSString *_name的成员变量
    class_addIvar(Car, "_name", sizeof(NSString*), log2(sizeof(NSString*)), @encode(NSString*));
    //动态添加一个int _num成员变量
    class_addIvar(Car, "_num", sizeof(int), sizeof(int), @encode(int));
    
    //注册方法名为sayHello的方法名
    SEL sel = sel_registerName("sayHello:");
    //动态添加sayHello的方法
    class_addMethod(Car, sel, (IMP)sayHelloFunction, "v@:@");
    
    //注册Car类
    objc_registerClassPair(Car);
    
    //创建Car的实例对象
    id carInstance = [[Car alloc] init];
    
    //从类中获取成员变量,并为成员变量赋值
    Ivar nameIvar = class_getInstanceVariable(Car, "_name");
    object_setIvar(carInstance, nameIvar, @"法拉利🚗");
    Ivar numIvar = class_getInstanceVariable(Car, "_num");
    object_setIvar(carInstance, numIvar, @4);
    
    //直接调用方法
    ((void (*)(id,SEL,id)) objc_msgSend)(carInstance,sel,@"跑起来了");
    
    //销毁类
    objc_disposeClassPair(Car);
    

    }
    </pre>
    <pre>
    //
    // People.m
    // runtimeDemo
    //
    // Created by aaron on 16/6/5.
    // Copyright © 2016年 aaron. All rights reserved.
    // 遍历获取类对象的成员变量和属性列表

    import "People.h"

    import <objc/runtime.h>

    @implementation People

    • (instancetype)initWithName:(NSString *)name reName:(NSString *)reName
      {
      self = [super init];
      if (self) {
      _name = name;
      _reName = reName;
      }

      return self;
      }

    • (NSDictionary *)allIvar
      {
      NSMutableDictionary *ivarDict = [NSMutableDictionary dictionary];

      unsigned int count;
      Ivar *ivarList = class_copyIvarList([self class], &count);
      for (int i = 0; i < count; i++) {

        Ivar ivar = ivarList[i];
        NSString *ivarName = [NSString stringWithUTF8String:ivar_getName(ivar)];
        id value = [self valueForKey:ivarName];
        if (value) {
            ivarDict[ivarName] = value;
        } else {
            ivarDict[ivarName] = [NSString stringWithFormat:@"key:%@对应的值为空",ivarName];
        }
      

      }
      free(ivarList);

      return ivarDict;
      }

    • (NSDictionary *)allProperty
      {
      NSMutableDictionary *propertyDict = [NSMutableDictionary dictionary];

      unsigned int count;
      objc_property_t *propertyList = class_copyPropertyList([self class], &count);
      for (int i = 0; i < count; i++) {

        objc_property_t property = propertyList[i];
        NSString *name = [NSString stringWithUTF8String:property_getName(property)];
        id value = [self valueForKey:name];
        if (value) {
            propertyDict[name] = value;
        } else {
            propertyDict[name] = [NSString stringWithFormat:@"key:%@对应的值为空",name];
        }
      

      }
      free(propertyList);

      return propertyDict;
      }

    @end
    </pre>

    相关文章

      网友评论

        本文标题:Objective-C Runtime 学习笔记之Objecti

        本文链接:https://www.haomeiwen.com/subject/exnzrttx.html