OC语言是基于C语言进行封装的一种面向对象的语言,因此OC的底层就是C,runtime则是用来链接OC与C,用C语言写的一个库,完成OC所不能完成的事,
以下是Runtime中比较常用的一些方法:
Ivar *class_copyIvarList(Class cls, unsigned int *outCount) //获取所有成员变量
const char *ivar_getName(Ivar v) 获取某个成员变量的名字
const char *ivar_getTypeEncoding(Ivar v) //获取某个成员变量的类型编码
Ivar class_getInstanceVariable(Class cls, const char *name) //获取某个类中指定名称的成员变量
id object_getIvar(id obj, Ivar ivar) //获取某个对象中的某个成员变量的值
void object_setIvar(id obj, Ivar ivar, id value) //设置某个对象的某个成员变量的值
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy) //为某个类关联某个对象
id objc_getAssociatedObject(id object, const void *key) //获取到某个类的某个关联对象
void objc_removeAssociatedObjects(id object) //移除已经关联的对象
在OC中,给一个类添加方法和可以使用延展,但使用延展的方法通常只能在本类中使用,在外界就访问不到了,如何才能在其他类中也使用这个类的私有方法和属性呢?
首先必须导入#import <objc/runtime.h>
//编码
- (void)encodeWithCoder:(NSCoder *)aCoder
{
unsigned int outCount;
Ivar *ivarList = class_copyIvarList([Person class], &outCount);
for (NSInteger i = 0; i < outCount; i++) {
const char *cName = ivar_getName(ivarList[i]);
NSString *name = [NSString stringWithUTF8String:cName];
[aCoder encodeObject:[self valueForKey:name] forKey:name];
}
}
//解码
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super init];
if (self) {
unsigned int outCount;
Ivar *ivarList = class_copyIvarList([Person class], &outCount);
for (NSInteger i = 0; i < outCount; i ++) {
const char *cName = ivar_getName(ivarList[i]);
NSString *name = [NSString stringWithUTF8String:cName];
[self setValue:[aDecoder decodeObjectForKey:name] forKey:name];
}
}
return self;
}
- (NSString *)description
{
/**
* class:要获取的类名
* @param outCount 通过这一个函数执行之后会将成员变量的个数赋值到此
* int * char * 表示int,char数组
*/
unsigned int outCount;
//获取到所有的成员变量
Ivar *ivarList = class_copyIvarList([Person class], &outCount);
for (NSInteger i = 0; i < outCount; i++) {
//每次获取一个成员变量
Ivar ivar = ivarList[i];
//获取成员变量的名字和类型编码
NSLog(@"name = %s,type = %s",ivar_getName(ivar),ivar_getTypeEncoding(ivar));
}
return nil;
}
然后在外界就可以使用这个类里面的属性和方法了
有时候,调用值申明没有实现的方法就会造成了程序Cresh,runtime中提供了了几个方法来避免这一问题
1 + resolveInstanceMethod:(SEL)sel // 为一个实例方法动态添加实现 + resolveClassMethod:(SEL)sel // 为一个类方法动态添加实现
2 - (id)forwardingTargetForSelector:(SEL)aSelector
//为没有实现的方法指定一个对象
3 - (void)forwardInvocation:(NSInvocation *)anInvocation
//子类重载这个方法为消息指定其他对象
比如我在.h中定义了walkOnTheStreet:这个方法,但是并没有在.m中实现,那可以调用使用以上几个方法来添加实现
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
NSString *selString = NSStringFromSelector(sel);
if ([selString isEqualToString:@"walkOnTheStreet:"]) {
为一个没有实现的方法动态添加实现
cls:类
IMP:要添加的实现
types:动态添加的实现的类型编码
class_addMethod(self, @selector(walkOnTheStreet:), (IMP)walkFunc, "V@:@");
}
return [super resolveInstanceMethod:sel];
}
有了这个方法,即使我们在viewDidLoad中调用没实现的方法也不会Cresh,runtime会帮我们实现,它的强大之处是实现方法可以在别的类中,只要和class_addMethod指定的方法名相同即可