runtime 的一些理解, 整理收集了不少网络的知识, 只是用于自己对runtime的理解,以备以后自己查阅吧
归纳: **
OC是运行时语言,只有在程序运行时,才会去确定对象的类型,并调用类与对象相应的方法。平时编写的OC代码, 在程序运行过程中, 其实最终都是转成了runtime的C语言代码, runtime算是OC的幕后工作者。利用runtime机制让我们可以在程序运行时动态修改类、对象中的所有属性、方法,就算是私有方法以及私有属性都是可以动态修改的。
runtime是属于OC的底层, 可以进行一些非常底层的操作。在程序运行过程中, 动态创建一个类, 动态地为某个类添加属性\方法, 修改属性值\方法,遍历一个类的所有成员变量(属性)\所有方法等。
相关知识点
Ivar:定义对象的实例变量,包括类型和名字。objc_property_t:定义属性。这个名字可能是为了防止和Objective-C 1.0中的用户类型冲突,那时候还没有属性。Method:成员方法。这个类型提供了方法的名字(就是选择器)、参数数量和类型,以及返回值(这些信息合起来称为方法的签名),还有一个指向代码的函数指针(也就是方法的实现**)。
SEL:定义选择器。选择器是方法名的唯一标识符,我理解它就是个字符串。
****运行时应用(一)****——** 拦截系统自带的方法交换实现**
- <objc/runtime.h>
2.<objc/message.h>
运行时应用(二)—— 使用对象关联为分类增加属性(每个对象的属性互不干扰)
1、对象的关联方法有
将某个值与某个对象关联起来,将某个值存储到某个对象中
利用参数key将对象中存储的对应值取出
2、利用分类为每个对象添加属性(可作为对象的标签或存储信息)
运行时应用(三)——实现NSCoding的自动归档和自动解档
当我们需要将一个对象进行归档时,都要让该对象的类遵守NSCoding协议,再实现归档和接档方法;
但当该类拥有上百个属性时,那将会花费更多的功夫在重复代码上,所以使用运行时runtime机制截取类的成员变量,进行赋值
补充: 在设计模式中: 如多态的一种适配器模式,就是使用的运行时,在程序过程中动态创建当前需要的类或者控制器, 也就是我们常说的封装一个基类,后面的都继承这个类,或者干脆在程序运行过程中动态创建;
详解:
Object - C运行时应用(一)—— 拦截系统自带的方法交换实现
一、什么是运行时
运行时是一套纯C语言的API,编译器最终都会将OC代码转化为运行时代码。
二、运行时常用函数
1、<objc/runtime.h>
* 获得某个类的类方法
Method class_getClassMethod(Class cls, SEL name)
* 获得某个对象的对象方法
Method class_getInstanceMethod(Class cls, SEL name)
* 交换两个方法的实现
void method_exchangeImplementations(Method m1, Method m2)
* 关联对象(将值value与对象object关联起来)
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
参数key:将来可以通过key取出这个存储的值
参数policy:存储策略(assign、copy、retain)
* 利用参数key将对象中存储的对应值取出
id objc_getAssociatedObject(id object, const void *key)
* 获得某个类的所有成员变量
Ivar *class_copyIvarList(Class cls, unsigned int *outCount)(outCount会返回成员变量的总数)
* 获得成员变量的名字
const char *ivar_getName(Ivar v)
* 获得成员变量的类型
const char *ivar_getTypeEncoding(Ivar v)
* 释放内存
void free(void *)
(当C语言函数名中包含了copy、create、retain、new等词语,那么就需要在最后释放资源)
2、<objc/message.h>
* 给某个对象发送某个消息
void objc_msgSend(void)
Object - C运行时应用(二)—— 使用对象关联为分类增加属性(每个对象的属性互不干扰)
一、对象的关联方法有
// 将某个值与某个对象关联起来,将某个值存储到某个对象中
1、 void objc_setAssociatedObject(id object, const void *key, id value,objc_AssociationPolicy policy) ,
关联对象(将值value与对象object关联起来)
参数key:将来可以通过key取出这个存储的值
参数policy:存储策略(assign、copy、retain)
2、 id objc_getAssociatedObject(id object, const void *key) ,
利用参数key将对象中存储的对应值取出
二、利用分类为每个对象添加属性(可作为对象的标签或存储信息)声明代码:
@interface NSObject (CX)
/**
* 为每一个对象添加一个name属性
*/
@property (nonatomic,copy) NSString *name;
/**
* 为每个对象添加一个数组属性
*/
@property (nonatomic,strong) NSArray *books;
@end
实现代码:
// 用一个字节来存储key值,设置为静态私有变量,避免外界修改
static char nameKey;
- (void)setName:(NSString *)name
{
// 将某个值与某个对象关联起来,将某个值存储到某个对象中
objc_setAssociatedObject(self, &nameKey, name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (NSString *)name
{
return objc_getAssociatedObject(self, &nameKey);
}
static char booksKey;
- (void)setBooks:(NSArray *)books
{
objc_setAssociatedObject(self, &booksKey, books, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSArray *)books
{
return objc_getAssociatedObject(self, &booksKey);
}
```
测试:
NSString *str = @"xx";
str.name = @"oo";
str.books = @[@"xxoo",@"ooxx"];
NSLog(@"%@,%@",str.name,str.books);
三、对象关联的另一种作用:在既有类中使用关联对象存放自定义数据
在ios开发时经常会用到UIAlertView类,该类提供了一种视图向用户展示警告信息。该类通过代理协议来处理用户的点击事件,但由于使用了代理就必须把创建警告的视图和处理按钮动作的代码分开;
####**运行时应用(三)——实现NSCoding的自动归档和自动解档**
当我们需要将一个对象进行归档时,都要让该对象的类遵守NSCoding协议,再实现归档和接档方法。
例如有一个Person类,该类有两个成员变量
@property (nonatomic,copy) NSString name;
@property (nonatomic,assign) int age;
两个协议的实现方法如下
/*
将对象写入某个文件时需要调用,在该方法中说明哪些属性需要存储
*/
- (void)encodeWithCoder:(NSCoder )encoder{
[encoder encodeObject:self.name forKey:@"name"];
[encoder encodeInt:self.age forKey:@"age"];
}
/* 从文件中解析对象时会调用,在该方法中解析对象的属性 */ - (id)initWithCoder:(NSCoder *)decoder{
if (self = [super init]) {
// 解析之后要赋值给属性
_name = [decoder decodeObjectForKey:@"name"];
_age = [decoder decodeIntForKey:@"age"];
}
return self;
}
但当该类拥有上百个属性时,那将会花费更多的功夫在重复代码上,所以使用运行时runtime机制截取类的成员变量,进行赋值