什么是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。
-
类与对象的继承层次关系如下图所示,非常经典的一张图
成员变量和属性
- 定义
//成员变量 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