美文网首页
runtime概述

runtime概述

作者: vicentwyh | 来源:发表于2018-06-14 11:31 被阅读0次

OC中runtime.h包含了OC中使用的一系列的底层C语言API声明

类的结构

typedef struct objc_class *Class; // 此声明在objc.h文件中
struct objc_class {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY; 指向类

#if !__OBJC2__
    Class _Nullable super_class     指向父类                          
    const char * _Nonnull name      类名                            
    long version                    版本相关信息,默认为0            
    long info                       提供运行期使用的标示符             
    long instance_size              当前类实例变量的大小                                 
    struct objc_ivar_list * _Nullable ivars                  成员变量列表
    struct objc_method_list * _Nullable * _Nullable methodLists  类中的方法相关信息列表       
    struct objc_cache * _Nonnull cache                       调用过的方法的相关信息列表               
    struct objc_protocol_list * _Nullable protocols          遵循的协议信息列表
#endif

} OBJC2_UNAVAILABLE;

可以看出:
1.Class是指向struct objc_class结构体类型的结构体指针
2.Class内部包含了指向对象类的isa指针和指向父类的super_class指针
3.ivars是指向objc_ivar_list结构体的指针,objc_ivar_list结构如下:

struct objc_ivar {
    char * _Nullable ivar_name        成员变量名                     
    char * _Nullable ivar_type        成员变量类型                     
    int ivar_offset                   指针偏移量             
#ifdef __LP64__
    int space                        占用的内存空间                        
#endif
}                                                           

struct objc_ivar_list {
    int ivar_count                                          
#ifdef __LP64__
    int space                                               
#endif
    /* variable length structure */
    struct objc_ivar ivar_list[1]                            
}                                                            

很显然ivars是个链表,内部包含了指向类中成员变量名称和成员变量类型的节点。
4.methodLists 也是链表,存储类中的方法相关信息,objc_method_list的结构在runtime.h中也能找到,这里不在展示。
5.cache链表:存储曾经调用过的方法的相关信息,这样将常用方法存到cache中,可以提高方法的查找效率。
6.protocols链表:存储当前类(包括父类)遵守的协议的相关信息。

底层函数

// 返回对象的副本
id object_copy(id obj, size_t size); 

// 释放对象占用的内存
id object_dispose(id obj);

// 返回对象的类
Class object_getClass(id obj);

// 设置对象的类型,并返回类型
Class object_setClass(id obj, Class cls);

// 判断对象是否是类或元类
BOOL object_isClass(id obj);

// 获取对象实例变量的值
id object_getIvar(id obj, Ivar ivar);

// 设置对象实例变量的值
void object_setIvar(id obj, Ivar ivar, id value);
void object_setIvarWithStrongDefault(id obj, Ivar ivar, id value);

// 修改类实例中实例变量的值
Ivar object_setInstanceVariableWithStrongDefault(id obj, const char *name
Ivar object_setInstanceVariable(id obj, const char *name, void *value);, void *value);

// 获取指定名称的类,指定类名不存在会调用类回调处理
Class objc_getClass(const char *name);
// 返回指定的元类
Class objc_getMetaClass(const char *name);
// 返回指定的类
Class objc_lookUpClass(const char *name)
Class objc_getRequiredClass(const char *name);

// 返回已注册的类定义的列表
int objc_getClassList(Class *buffer, int bufferCount);
// 创建并返回一个指向所有已注册类的列表指针
Class *objc_copyClassList(unsigned int *outCount);

// 返回类名
const char *class_getName(Class cls) 

// 是否是元类
BOOL class_isMetaClass(Class cls);

// 返回类的父类
Class class_getSuperclass(Class cls);

// 给类指定一个父类,并返回旧的父类
Class class_setSuperclass(Class cls, Class newSuper);

// 返回类的版本号
OBJC_EXPORT int class_getVersion(Class cls);
// 设置类版本号
void class_setVersion(Class cls, int version);
// 返回实例类的大小
size_t class_getInstanceSize(Class cls);
// 返回类中指定名称实例变量的信息
Ivar class_getInstanceVariable(Class cls, const char *name);

// 返回类中指定名称实例成员变量的信息
Ivar class_getInstanceVariable(Class cls, const char *name);
// 返回类指定名称变量的信息
Ivar class_getClassVariable(Class cls, const char *name);

// 返回整个成员变量列表
Ivar *class_copyIvarList(Class cls, unsigned int *outCount);

// 返回类中指定实例方法
Method class_getInstanceMethod(Class cls, SEL name);
// 返回类中指定的类方法
Method class_getClassMethod(Class cls, SEL name);
// 返回类中所有方法的列表
Method *class_copyMethodList(Class cls, unsigned int *outCount);
// 返回类方法的入口指针
IMP class_getMethodImplementation(Class cls, SEL name);
// 返回类方法实现的指针
IMP class_getMethodImplementation_stret(Class cls, SEL name);
/* An opaque type that represents a method in a class definition.
   Method是objc_method结构体类型指针
   objc_method结构体,包含了方法方法的名称,参数类型以及方法实现的入口指针(IMP)
*/ 
typedef struct objc_method *Method;
struct objc_method {
    SEL method_name                                 
    char * method_types                           
    IMP  method_imp                                  
}   
#if !OBJC_OLD_DISPATCH_PROTOTYPES
typedef void (*IMP)(void /* id, SEL, ... */ ); 
#else
typedef id _Nullable (*IMP)(id _Nonnull, SEL _Nonnull, ...); 
#endif

// 类的实例是否响应指定的方法
BOOL class_respondsToSelector(Class cls, SEL sel);

// 返回类是否实现指定的协议
BOOL class_conformsToProtocol(Class cls, Protocol *protocol);
// 返回这个类所遵循的协议
Protocol ** class_copyProtocolList(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)

注意:class_copyPropertyList 和 class_copyIvarList 是不同的,前者获取的只是类中声明的属性变量,后者则是获取类中的实例变量

@interface Person : NSObject
{
    NSString *_name;
}
@property (nonatomic, assign) int sex;
@property (nonatomic, assign) int age;
@property (nonatomic, copy) NSString *tele;
@end
---------------------------------------------------------------------------------------------
- (void)viewDidLoad {
    [super viewDidLoad];
    uint count = 0;
    Ivar *ivarList = class_copyIvarList(objc_getClass("Person"), &count);
    for (int i = 0; i < count; i++) {
        NSString *ivarName = [NSString stringWithUTF8String:ivar_getName(ivarList[i])];
        NSLog(@"ivarName:%@",ivarName);
    }
    NSLog(@"---------------------------");
    uint count2= 0;
    objc_property_t *properties = class_copyPropertyList(objc_getClass("Person"), &count2);

    for (int i = 0; i < count2; i++) {
        NSString *propertyName = [NSString stringWithUTF8String:property_getName(properties[i])];
        NSLog(@"propertyName:%@",propertyName);
    }
--------------------------------------console------------------------------------------------
[1037:59125] ivarName:_name
[1037:59125] ivarName:_sex
[1037:59125] ivarName:_age
[1037:59125] ivarName:_tele
 ---------------------------
[1037:59125] propertyName:sex
[1037:59125] propertyName:age
[1037:59125] propertyName:tele
// 获取类中强引用成员变量的布局
const uint8_t *class_getIvarLayout(Class cls);
// 设置变量布局
void class_setIvarLayout(Class cls, const uint8_t *layout);
// 获取类中弱引用成员变量的布局
uint8_t *class_getWeakIvarLayout(Class cls);
// 设置弱属性的变量布局
void class_setWeakIvarLayout(Class cls, const uint8_t *layout)

ivar 的修饰信息在Class 的 Ivar Layout 中,具体看objc-runtime-new.hOC Class Ivar Layout 探索

struct class_ro_t {
    uint32_t flags;
    uint32_t instanceStart;
    uint32_t instanceSize;
#ifdef __LP64__
    uint32_t reserved;
#endif
    const uint8_t * ivarLayout; // 存储 strong 的 ivar
    const char * name;
    method_list_t * baseMethodList;
    protocol_list_t * baseProtocols;
    const ivar_list_t * ivars;

    const uint8_t * weakIvarLayout; // 存储 weak 的 ivar
    property_list_t *baseProperties;

    method_list_t *baseMethods() const {
        return baseMethodList;
    }
};
// 为类添加新的方法
BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types) 
// 方法存在时替代方法的实现,方法不存在时相当于class_addMethod
IMP class_replaceMethod(Class cls, SEL name, IMP imp,  const char * types) 

// 为类添加实例变量
class_addIvar(Class cls, const char * name, size_t size, uint8_t alignment, const char * types) 
// 为类添加新的协议
class_addProtocol(Class cls, Protocol *protocol) ;
// 添加属性
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);

// 通过CoreFoundation's自由连接。不能自己调用此方法
Class objc_getFutureClass(const char *name);
// 创建类实例
id class_createInstance(Class cls, size_t extraBytes);
// 在指定位置创建类实例
id objc_constructInstance(Class cls, void *bytes);
// 在不释放内存的情况下销毁类的实例,并删除此实例可能具有的任何关联引用。
void *objc_destructInstance(id obj) 
// 创建新的类
Class objc_allocateClassPair(Class superclass, const char *name, size_t extraBytes);
// 注册由objc_allocateClassPair创建的类
void objc_registerClassPair(Class cls) 

以上两个函数一起创建一个新的类
例如创建一个新的类Person,继承与NSObject:

Class newCls = objc_allocateClassPair([NSObject class], "Person", 0);
objc_registerClassPair(newCls);
// 用于KVO观察者模式。 不能自己调用此方法
Class objc_duplicateClass(Class original, const char * name, size_t extraBytes)
// 销毁一个类及其相关联的类
void objc_disposeClassPair(Class cls);
// 返回方法的名称
SEL method_getName(Method m);
// 返回一个函数指针
IMP method_getImplementation(Method m)

上面这两个方法是不一样。
前者:返回的SEL是一个objc_selector结构体类型指针:
/// An opaque type that represents a method selector.
typedef struct objc_selector *SEL;

Mac OSX仅仅将SEL映射为C字符串所以相同的方法名具有相同的SEL编号,即使它们属于不同的类

后者:返回的IMP本质上是一个函数指针的别名,直接指向函数在内存中的入口实现地址,而无需通过消息传递定位
#if !OBJC_OLD_DISPATCH_PROTOTYPES
typedef void (*IMP)(void /* id, SEL, ... */ ); 
#else
typedef id _Nullable (*IMP)(id _Nonnull, SEL _Nonnull, ...); 
#endif
// 返回方法接收参数的个数
注意所有函数都有两个隐藏的参数SEL和_cmd,所以参数个数会多+2
unsigned int method_getNumberOfArguments(Method m);
// 返回描述方法返回类型的字符串
char *method_copyReturnType(Method m)
// 返回描述方法单个参数类型的字符串
char *method_copyArgumentType(Method m, unsigned int index)
// 通过引用返回描述方法的返回类型
void method_getReturnType(Method m, char *dst, size_t dst_len) 
// 通过引用返回描述方法的单个参数类型
void method_getArgumentType(Method m, unsigned int index, char *dst, size_t dst_len);
// 返回指定方法的结构描述
struct objc_method_description *method_getDescription(Method m);

struct objc_method_description {
    SEL name;               方法名
    char *types;          参数类型
};

具体参考:Type Encodings

// 设置方法的入口实现地址
IMP method_setImplementation(Method m, IMP imp);
// 交换两个方法的实现入口地址
void method_exchangeImplementations(Method m1, Method m2);

ivar

// 返回实例变量的名称
const char *ivar_getName(Ivar v);
// 返回实例变量类型字符串
const char *ivar_getTypeEncoding(Ivar v);
// 返回实例变量的偏移量
ptrdiff_t ivar_getOffset(Ivar v);

property

// 返回属性名称
const char *property_getName(objc_property_t property);
// 返回属性的属性字符串
const char *property_getAttributes(objc_property_t property);
// 返回属性的属性数组
objc_property_attribute_t *property_copyAttributeList(objc_property_t property, unsigned int *outCount);
// 返回指定属性名称的属性的值
char *property_copyAttributeValue(objc_property_t property, const char *attributeName);

protocol

// 返回指定名称的协议
Protocol *objc_getProtocol(const char *name);
// 返回runtime已知的所有协议的数组
Protocol * __unsafe_unretained *objc_copyProtocolList(unsigned int *outCount);
// 判断一个协议是否遵循了另一个协议
BOOL protocol_conformsToProtocol(Protocol *proto, Protocol *other);
// 判断两个协议是否相等
BOOL protocol_isEqual(Protocol *proto, Protocol *other);
// 返回协议的名称
const char *protocol_getName(Protocol *p);
// 获取协议中指定方法的方法描述
struct objc_method_description protocol_getMethodDescription ( Protocol *p, SEL aSel, BOOL isRequiredMethod, BOOL isInstanceMethod );
// 获取协议中指定条件的方法的方法描述数组
struct objc_method_description * protocol_copyMethodDescriptionList ( Protocol *p, BOOL isRequiredMethod, BOOL isInstanceMethod, unsigned int *outCount );
// 获取协议的指定属性
objc_property_t protocol_getProperty ( Protocol *proto, const char *name, BOOL isRequiredProperty, BOOL isInstanceProperty );
// 获取协议中的属性列表
objc_property_t * protocol_copyPropertyList ( Protocol *proto, unsigned int *outCount );
// 返回协议中声明的属性列表
objc_property_t *protocol_copyPropertyList2(Protocol *proto, unsigned int *outCount, BOOL isRequiredProperty, BOOL isInstanceProperty)
// 获取协议遵循的协议
Protocol ** protocol_copyProtocolList ( Protocol *proto, unsigned int *outCount );
// 创建新的协议实例
Protocol * objc_allocateProtocol ( const char *name );
// 在运行时中注册新创建的协议
void objc_registerProtocol ( Protocol *proto );
// 向协议中添加方法,必须在协议未注册之前
void protocol_addMethodDescription ( Protocol *proto, SEL name, const char *types, BOOL isRequiredMethod, BOOL isInstanceMethod );
//添加一个已注册的协议到未注册的协议中
void protocol_addProtocol ( Protocol *proto, Protocol *addition );
// 为协议添加属性,必须在协议注册之前
void protocol_addProperty ( Protocol *proto, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount, BOOL isRequiredProperty, BOOL isInstanceProperty );
// 返回所有加载的Objective-C框架和动态库的名称
const char **objc_copyImageNames(unsigned int *outCount) 
// 返回一个类所在的动态库名称
const char *class_getImageName(Class cls);
// 返回库中所有类的名称
const char **objc_copyClassNamesForImage(const char *image,unsigned int *outCount);

// 返回指定sel的方法的名称
const char *sel_getName(SEL sel);
// 使用OC运行时系统注册一个方法,将方法名映射到选择器SEL并返回SEL值
SEL sel_registerName(const char *str);
// 判断两个sel是否相同
BOOL sel_isEqual(SEL lhs, SEL rhs);

// 在每次迭代中检测到突变时,编译器插入此函数。 它在变异发生时被调用,并且如果设置了enumerationMutationHandler,则会执行。 如果未设置处理程序,则会发生致命错误。
void objc_enumerationMutation(id obj) 
// 设置当前突变的处理程序
OBJC_EXPORT void objc_setEnumerationMutationHandler(void (*handler)(id));
// 设置objc_msgForward调用的函数。
void objc_setForwardHandler(void *fwd, void *fwd_stret) 

// 创建一个当调用此方法时调用指定块的函数指针
 IMP imp_implementationWithBlock(id block);
// 返回与使用imp_implementationWithBlock创建的IMP关联的块
id imp_getBlock(IMP anImp);
// 移除与使用imp_implementationWithBlock创建的IMP相关联的块的关联
BOOL imp_removeBlock(IMP anImp)

// 加载弱指针引用的对象并返回它
id objc_loadWeak(id *location);
// 存储_weak变量的新值
id objc_storeWeak(id *location, id obj);

// 设置对象对应key和和关联策略的关联值
void objc_setAssociatedObject(id object, const void *key,  id value, objc_AssociationPolicy policy)
// 获取对象给定key的关联值
OBJC_EXPORT id objc_getAssociatedObject(id object, const void *key);
// 移除对象的所有关联
void objc_removeAssociatedObjects(id object);

相关文章

  • runtime概述

    OC中runtime.h包含了OC中使用的一系列的底层C语言API声明 类的结构 可以看出:1.Class是指向s...

  • Runtime概述

    很多学习Object-C的小伙伴经常花大部分时间去学习OC的语法、Cocoa框架、以及第三方的框架,以至于忽略了O...

  • iOS - Runtime - 概念和方法交换

    runtime的概述runtime的相关概念runtime消息机制消息传递动态方法解析消息转发runtime的作用...

  • Runtime

    概述 runtime 是什么 isa指针 runtime 怎么添加属性,方法等 runtime 如何实现weak属...

  • Objective-C 2.0运行时系统编程指南

    runtime指南官方地址: Objective-C Runtime Programming Guide 概述 O...

  • Runtime常用的几个应用场景

    概述 接上篇《Runtime基本原理及Demo》,了解了Runtime相关基础知识后,我们谈一下Runtime常见...

  • Runtime常用的几个应用场景

    概述 接上篇《Runtime基本原理及Demo》,了解了Runtime相关基础知识后,我们谈一下Runtime常见...

  • 认识Objective-C的Block

    简介 概述 Block objects are a C-level syntactic and runtime f...

  • Node.js快速入门

    一、概述 Node.js® is a JavaScript runtime built on Chrome's V...

  • Objective C Runtime概述

    一、概述 Objective-C语言是一门动态语言,它将很多静态语言在编译和链接期所做的事推迟到运行时处理。这种动...

网友评论

      本文标题:runtime概述

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