- 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
- 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
查看更多
JSPatch实现原理详解让JS调用替换任意OC方法概要1
JSPatch实现原理详解:让JS调用/替换任意OC方法JSPatch以小巧的体积做到了让JS调用/替换任意OC方法,让iOS APP具备热更新的能力,在实现 JSPatch 过程中遇到过很多困难也踩过很多坑,有些还是挺值得分享的。本篇文章从基础原理、方法调用和方法替换三块内容介绍整个 JSPatch 的实现原理,并把实现过程中的想法和碰到的坑也尽可能记录下来。基础原理能做到通过JS调用和改写OC方法最根本的原因是 Objective-C 是动态语言,OC上所有方法的调用/类的生成都通过 Objective-C Runtime 在运行时进行,我们可以通过类名/方法名反射得到相应的类和方法:Class?class?=?NSClassFromString(UIViewController);?id?viewController?=?[[class?alloc]?init];?SEL?selector?=?NSSelectorFromString(viewDidLoad);?[viewController?performSelector:selector];?也可以替换某个类的方法为新的实现:static?void?newViewDidLoad(id?slf,?SEL?sel)?{}?class_replaceMethod(class,?selector,?newViewDidLoad,?@);?还可以新注册一个类,为类添加方法:Class?cls?=?objc_allocateClassPair(superCls,?JPObject,?0);?objc_registerClassPair(cls);?class_addMethod(cls,?selector,?implement,?typedesc);?对于 Objective-C 对象模型和动态消息发送的原理已有很多文章阐述得很详细,例如这篇,这里就不详细阐述了。理论上你可以在运行时通过类名/方法名调用到任何OC方法,替换任何类的实现以及新增任意类。所以 JSPatch 的原理就是:JS传递字符串给OC,OC通过 Runtime 接口调用和替换OC方法。这是最基础的原理,实际实现过程还有很多怪要打,接下来看看具体是怎样实现的。方法调用require(UIView)?var?view?=?UIView.alloc().init()?view.setBackgroundColor(require(UIColor).grayColor())?view.setAlpha(0.5)?引入JSPatch后,可以通过以上JS代码创建了一个 UIView 实例,并设置背景颜色和透明度,涵盖了require引入类,JS调用接口,消息传递,对象持有和转换,参数转换这五个方面,接下来逐一看看具体实现。1.require调用 require(‘UIView’) 后,就可以直接使用 UIView 这个变量去调用相应的类方法了,require 做的事很简单,就是在JS全局作用域上创建一个同名变量,变量指向一个对象,对象属性__isCls表明这是一个 Class,__clsName保存类名,在调用方法时会用到这两个属性。var?_require?=?function(clsName)?{?if?(!global[clsName])?{?global[clsName]?=?{?__isCls:?1,?__clsName:?clsName?}?}?return?global[clsName]?}?所以调用require(‘UIView’)后,就在全局作用域生成了 UIView 这个变量,指向一个这样一个对象:{?__isCls:?1,?__clsName:?UIView?}?2.JS接口接下来看看 UIView.alloc() 是怎样调用的。旧实现对于这个调用的实现,一开始我的想法是,根据JS特性,若要让 UIView.alloc() 这句调用不出错,唯一的方法就是给 UIView 这个对象添加 alloc 方法,不然是不可能调用成功的,JS对于调用没定义的属性/变量,只会马上抛出异常,而不像OC/Lua/ruby那样会有转发机制。所以做了一个复杂的事,就是在require生成类对象时,把类名传入OC,OC通过 Runtime 方法找出这个类所有的方法返回给JS,JS类对象为每个方法名都生成一个函数,函数内容就是拿着方法名去OC调用相应方法。生成的 UIView 对象大致是这样的:{?__isCls:?1,?__clsName:?UIView,?alloc:?function()?{…},?beginAnimations_context:?function()?{…},?setAnimationsEnabled
文档评论(0)