OC具有相当多的动态性,基本的,也是经常被提到和用到的有动态类型,动态绑定以及动态加载。
1.动态类型
运行时再决定对象的类型。这类动态性在常应用中非常的常见,简单来说就是id类型。id类型即通用的对象类型,任何对象都可以被id指针所指。
2.动态绑定
基于动态类型,在某个实例对象被确定后,其类型便被确定了。该对象对应的属性和响应的消息也被完全确定,这就是动态绑定。由于OC的动态特性,在OC中其实很少提及“函数”的概念,传统的函数一般在编译时就已经把参数信息和函数实现打包到编译后的源码中了,而在OC中最常使用的是消息机制。调用一个实例的方法,所做的是向该实例的指针发送消息,实例在收到消息后,从自身的实现中寻找响应这条消息的方法。
3.动态加载
根据需求加载所需要的资源,这点很容易理解,对于iOS开发来说,基本就是根据不同的机型做适配。最经典的例子就是在Retina设备上加载@2x的图片,而在老一些的普通屏设备上加载原图。随着Retina iPad的推出,和之后可能的Retina Mac的出现,这个特性相信会被越来越多地使用。
下面我们来看一下runtime的使用:
1.交换两个方法
由于一个oc类的+(void)load方法是在app开始运行的时候首先会被调用的方法,也就是说,当一个app被点击,再被系统加载app程序进入到内存的时候,首先会实例所有类到代码或者全局变量,而在加载所有类的设置的时候,会走+(void)load方法,而且该方法在main函数之前走,因此我们在该方法内实现两个函数的交换。在这里举一个例子:新建一个继承自UIImage的分类,然后在分类中添加一个方法
然后在+(void)load方法里面实现下列的方法
+(void)load
{
//获取系统自带的方法
Method originalSystemMethod =class_getClassMethod([self class],@selector(imageNamed:));
//获取自己自定义的方法
Method newMethod =class_getClassMethod([self class],@selector(imageWithImageName:));
//交换两个方法的实现
method_exchangeImplementations(originalSystemMethod, newMethod);
}
然后实现下面的方法
+(UIImage*)imageWithImageName:(NSString*)imageName
{
UIImage* image =[UIImage imageWithImageName:imageName];
if(! image) {
NSLog(@"图片不存在");
}
return image;
}
然后我们在相应的需要用到的地方运用:
//这里用到了runtime的替换了系统的方法,因为系统自带的方法有局限性。
UIImage* image =[UIImage imageNamed:@"wx_Withdrawals@3x.png"];
2.动态的添加成员属性。
我们可以给一个分类添加方法,但是如果给一个分类添加成员属性的话,我们就需要手动的去实现该成员属性的set与get方法。此时我们就需要用到runtime。下面以继承自UIControl的分类为例。
下面来解释一下参数的意义:
/*
id object :即我们要给谁添加属性
const coid * key: 即一个key值 我们根据这个key值去找到需要添加的成员属性
id value: 即我们要添加的成员属性
objc_AssociationPolicy :关联政策 ,它是一个枚举类型的值
objc_setAssociatedObject(<#id object#>, <#const void *key#>, <#id value#>, objc_AssociationPolicy policy)
*/
这样我们就完成了利用runtime来动态的添加成员属性。
3.动态添加方法
所谓的动态添加方法就是动态的去判断一个类方法有没有实现,如果没有实现,就动态的去添加。下面以继承自NSObject的Student类为例子。在这里就直接上代码了。
然后我们在相应的地方去运用
Student * student =[ Student new];
[student formSelector:@selector(study)];
这样我们就成功的为一个类动态的添加了实例化方法。
4.动态绑定(动态转发)
当我们给一个实例添加一个没有实现的方法的时候 系统一般会给出三种措施来防止系统的崩溃
第一种方法就是在+(BOOL)resolveInstanceMethod:(SEL)sel方法中去实现(详情请参考上面的代码)
如果第一种方法没有实现的话系统就会有第二种方法 :
第二种: -(id)forwardingTargetForSelector:(SEL)aSelector在这个方法里面我们让我们要转发的对象去实现上述没有实现的方法
如果以上都不进行处理,就会来到下面的两个方法
我们自己创建自己的方法签名,然后在forwardInvocation中用你要转发的那个对象调用对应的签名
第三个方法: -(NSMethodSignature*)methodSignatureForSelector:(SEL)aSelector 与 -(void)forwardInvocation:(NSInvocation*)anInvocation
下面以例子说明:我创建了一个Studnet的类 一个Bird类
我们现在写了一行代码
Student* student = [Student new];
[student performSelector:@selector(fly)];
然后在Student类里面实现下面的方法
这样我们就把student的方法转给了Bird类。
以上是自己对OC的runtime的一点理解。
欢迎到github上面下载:
下载地址: