1.require
在全局作用域上创建一个同名变量,指向一个对象。
{ __isCls: 1, __clsName: "UIView" }
2.UIView.alloc
__c元函数 :调用一个不存在方法时,转发到一个指定函数去执行。
在oc执行JS脚本前,通过正则把所有的方法调用改成调用__c函数,再执行JS脚本。如:
UIView.alloc().init() -> UIView.__c('alloc')().__c('init')()
并给JS对象的基类Object添加__c成员变量,其所有子类都可调用__c.
return _methodFunc(self.__obj, self.__clsName, methodName, args, self.__isSuper)
把要调用的类名和oc方法传递给oc。
3.传递消息
JSContext *context = [[JSContext alloc] init]; context[@"hello"] = ^(NSString *msg) { NSLog(@"hello %@", msg); }; [_context evaluateScript:@"hello('word')"];
OC提供了一个JavaScriptCore 库,用来和js进行交互。
JSContext 是JS代码的执行环境,可以给JSContext添加方法。如上代码,就是给Context添加hello方法。
evaluateScript("var num = 5+5 ")-->运动JS代码。
JSValue包装了可能是JS的值(字符串,数字,数组,字典,对象,方法等)。
4.对象方法
如:UIView.alloc().
这个对象在 JS 无法使用,但在回传给 OC 时 OC 可以找到这个对象。然后返回一个对象指针给JS,在__c函数里把这个对象指针以及它要调用的方法名传给oc。
将oc对象封装成一个字典的形式:{__obj: [OC Object 对象指针]}。
5.类型转换
JS 把要调用的类名/方法名/对象传给 OC 后,OC 调用类/对象相应的方法是通过 NSInvocation 实现
a.取得要调用的 OC 方法各参数类型,把 JS 传来的对象转为要求的类型进行调用。
b.根据返回值类型取出返回值,包装为对象传回给 JS。
6.方法替换 forwardInvocation
让每个需要被js替换的方法调用最后都调用-forwardInvocation。
-
把UIViewController的
-viewWillAppear:
方法通过class_replaceMethod()
接口指向_objc_msgForward
,这是一个全局 IMP,OC 调用方法不存在时都会转发到这个 IMP 上,这里直接把方法替换成这个 IMP,这样调用这个方法时就会走到-forwardInvocation:
。 -
为UIViewController添加
-ORIGviewWillAppear:
和-_JPviewWillAppear:
两个方法,前者指向原来的IMP实现,后者是新的实现,稍后会在这个实现里回调JS函数。 -
改写UIViewController的
-forwardInvocation:
方法为自定义实现。一旦OC里调用 UIViewController 的-viewWillAppear:
方法,经过上面的处理会把这个调用转发到-forwardInvocation:
,这时已经组装好了一个 NSInvocation,包含了这个调用的参数。在这里把参数从 NSInvocation 反解出来,带着参数调用上述新增加的方法-JPviewWillAppear:
,在这个新方法里取到参数传给JS,调用JS的实现函数。 - 在替换
-forwardInvocation:
方法前会新建一个方法-ORIGforwardInvocation:
,保存原来的实现IMP,在新的-forwardInvocation:
实现里做了个判断,如果转发的方法是我们想改写的,就走我们的逻辑,若不是,就调-ORIGforwardInvocation:
走原来的流程。
6.新增方法
defineClass
定义的方法会经过 JS 包装,变成一个包含参数个数和方法实体的数组传给OC,OC会判断如果方法已存在,就执行替换的操作,若不存在,就调用 class_addMethod()
新增一个方法,通过传过来的参数个数和方法实体生成新的 Method,把 Method 的参数和返回值类型都设为id。这里 JS 调用新增方法走的流程还是 forwardInvocation
这一套。
a. 协议:
参数不全为id:
在 JS 定义类时给出实现的 protocol,这样在新增 Protocol 里已定义的方法时,参数类型会按照 Protocol 里的定义去实现:
defineClass("JPViewController: UIViewController <UIAlertViewDelegate>", { alertView_clickedButtonAtIndex: function(alertView, buttonIndex) { console.log('clicked index ' + buttonIndex) } })
b.属性
通过set和get方法给对象动态添加成员变量(关联)
7 self 和super关键字
self:在js中为全局变量,调用前,self=当前对象,调用后置空。
super 添加__isSuper:1 oc中,调用super方法,找到superClass的IMP,新增一个方法,指向这个IMP.调用这个方法。