Objective-C Runtime 学习笔记之Objective-C的元素认知

什么是Runtime

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

类和对象


/// 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;
};

  • 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。
  • 类与对象的继承层次关系如下图所示,非常经典的一张图


    Objective-C Runtime 学习笔记之Objective-C的元素认知_第1张图片
    类与对象的继承层次关系图

成员变量和属性

  • 定义


//成员变量 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

}


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

  • 常用方法


// 获取类中指定名称实例成员变量的信息
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 );


// 获取指定的属性
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 );

方法(SEL,IMP,METHOD)

  • Method代表类中的某个方法的类型


    typedef struct objc_method *Method;
    struct objc_method {
    SEL method_name OBJC2_UNAVAILABLE; // 方法名
    char *method_types OBJC2_UNAVAILABLE; // 方法类型
    IMP method_imp OBJC2_UNAVAILABLE; // 方法实现
    }

  • Sel 代表方法名


    typedef struct objc_selector *SEL;
    struct objc_selector {
    *name; OBJC2_UNAVAILABLE;// 名称
    char *types; OBJC2_UNAVAILABLE;// 类型
    };

  • IMP 表示方法实现,实际是一个函数指针


    typedef id (*IMP)(id, SEL, ...);

  • 常用方法


    // 添加类方法
    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 );

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

runtime实践


/**

  • 创建一个方法,并用两种方法获取成员变量的值
  • @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);

}



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

import "People.h"

import

@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

你可能感兴趣的:(Objective-C Runtime 学习笔记之Objective-C的元素认知)