前言我们知道静态语言在编译时就已经确定了函数的具体调用,而动态语言要到运行时才能真正确定调用哪个函数;Objective-C是一门动态语言,它运行通过定时机制实现的Runtime。Runtime虽然是相对于底层的一种机制,但是在项目过程中经常会用到它来解决一些问题。下面我们就来看看使用Runtime可以解决项目中的哪些问题。项目中Runtime实现的功能是使用关联对象为分类添加伪属性。在项目开发中,经常会遇到给已有类添加属性的情况。面对这种情况,我们一般会创建一个类来给已有的类添加属性,但是由于类结构的特殊性,给类添加属性并不会自动为我们创建实例变量和存储方法。首先我们要知道,在定义一个@property的时候,编译器会帮我们做三件事:生成实例变量_property生成getter方法生成setter方法但是在分类中,它们不会帮我们生成实例变量和访问方法,所以我们需要自己实现访问方法。这里我们将通过关联对象,将键值与对象关联起来。以下是代码示例:@property(nonatomic,strong)NSString*title;-(NSString*)title{returnobjc_getAssociatedObject(self,_cmd);}-(void)setTitle:(NSString*)title{objc_setAssociatedObject(self,@selector(title),title,OBJC_ASSOCIATION_RETAIN);}我们暂时只讲如何通过关联对象的属性给分类添加伪属性,至于为什么分类不自动为我们添加实例变量和访问方法,以及关联对象的实现原理等,我们会在后面的面试题中继续涉及到这个话题。使用MethodSwizzling交换方法,我们可以使用MethodSwizzling来交换两个方法的实现,从而达到Hook的效果;比如交换ViewController的生命周期方法实现页面嵌入,或者在不影响原有功能的情况下增加一些特殊的功能。swap方法主要是通过Runtime中的class_addMethod、class_replaceMethod、method_exchangeImplementations方法实现的。以下是MethodSwizzling代码的示例:class_getInstanceMethod(class,originalSeletor);MethodswizzledMethod=class_getInstanceMethod(class,swizzledSeletor);//首先尝试在sourceSEL中加入IMP,这里是为了避免sourceSEL的IMP情况BOOLdidAddMethod=class_addMethod(class,originalSeletor,method_getImplementation(swizzledMethod),method_getTypeEncoding(swizzledMethod));if(didAddMethod){//添加成功:说明源SEL没有实现IMP,将源SEL的IMP替换为交易所的IMPSELclass_replaceMethod(class,swizzledSeletor,method_getImplementation(originMethod),method_getTypeEncoding(originMethod));}else{//添加失败:说明源SEL已经有IMP,只是交换两个SEL的IMPmethod_exchangeImplementations(originMethod,swizzledMethod);}}使用class_copyIvarList实现NSCoding的自动返回使用NSKeyedArchiver对对象进行归档和解归档时,对象Model需要实现NSCoding协议,实现encodeWithCoder和initWithCoder方法。在这两种方法中,必须对每个属性进行code和encode,否则会crash在项目开发过程中,Model中的属性经常变化。这时候总是忘记修改相应的属性code和encode,会导致crash;为了避免这种现象,让Model中的方法更加简洁易控制,这里我们将使用class_copyIvarList获取对象中的成员变量列表,然后使用KVC进行编码编码。示例代码如下:(这里我们把这个通用代码抽象成一个宏,以便在需要的Model中直接调用)#definePXYNSCodingRuntime_EncodeWithCoder(Class)\unsignedintoutCount=0;\Ivar*ivars=class_copyIvarList([Classclass],&outCount);\for(inti=0;i
