接触JSPatch也快一年,在此总结归纳一些新接触的开发者容易碰到的一些问题。其实很多问题bang哥在wiki中已经写的很详细了,建议花点时间仔细看看下面这两个WiKi内容。
想要了解JSPatch实现原理可以先看 JSPatch 实现原理详解
require导入类
只需要一对' '
, 多个类之间用逗号 ,
分隔:1
require('UIView, UIColor')
方法遇到下划线_
需要特别注意
因为JSPatch是通过_
来分割方法参数的,所以遇到方法本身带有_
的时候需要使用__
双下划线代替,否则会被识别成一个参数,导致出现类似如下的报错。
1 | //OC方法代码如下 |
我们知道selector 的 一个:
代表有一个参数,结合报错信息可知runtime所找的方法是带两个参数的,所以肯定跟你需要调用的方法不一致,找不到则会导致崩溃。
把JS调用代码改为下面这种即可,每个下划线_
变成双_
,同理如果你方法中本身是双下划线__
则需要变成____
四个下划线。
1
2//JS正确调用代码如下
var testBool = self.__test__Bool();
如果需要替换的方法本身带有下划线,与方法调用相同,也同样需要双下划线__
1
2
3
4__test__Bool:function(){
console.log("我是js testBool");
return YES;
}
undefined is not an object(evaluating ‘self.__c’)
提示意思是self这个对象不存在,结合JSPatch的使用场景可以推测出这个错误一般是由于在block中使用self引起的,解决办法参考block 里使用 self 变量。但值得注意的是,在JS中,如果报了类似的undefined is not an object aaa.bbb错误,则是因为aaa这个对象为undefined,而你又要访问一个undefined的对象属性或者方法在JS中会导致崩溃。
一个最简单高效获取对象类名方法
大多数需求场景下可以通过object.__clsName
的方式获取OC对象类名。不需要通过isKindOfClass或者NSStringFromClass(此方法需要预先添加C函数扩展)来获取,而且不需要与OC相互通信。1
2
3
4
5//替换按钮点击方法
handleBtn: function(sender) {
var btnClassName = sender.__clsName;
console.log("btnClassName is : " + btnClassName);
}
下面列举一些有__clsName
属性的OC对象情况。
- JSPatch 通过hook消息转发forwardInvocation: 方法,在调用替换方法或者新添加的方法时给参数添加了
__clsName
标记来保存类名(所以类似图一的sender参数就会有__clsName属性),但是Class、NSNumber、BOOL、CGFloat、结构体不知道还有没有o(╯□╰)o,感兴趣的可以去查看源码
除外。 - 通过 require 引入的类,所以在JS内通过init出来的对象都会有
__clsName
属性。 - 属性和私有变量值和方法返回值(Class、NSNumber、BOOL、CGFloat、结构体…除外,不过这些好像需要知道类名情况比较少)
- 欢迎补充
OC对象和JS对象
大家在JSPatch交流群里所说的OC对象指的是从OC中获取的JS对象如var str = self.str()
或 通过JS初始化的对象var str = NSString.stringWithFormat("Hello World")
,而JS对象指的是例如 var str = "我是js对象"
或var str = self.str().toJS()
之后的JS对象。OC对象应该使用OC中相应方法,JS对象应该使用JS中相应方法。1
2
3
4
5
6
7
8
9
10
11
12
13
14//替换按钮点击方法
handleBtn: function(sender) {
var btnClassName = sender.__clsName;
console.log("btnClassName is : " + btnClassName);
//初始化的OC对象
var ocInitStr = NSString.stringWithFormat("Hello World")
//获取属性得到的OC对象
var str = self.str();
console.log("ocInitStr 截取前5个字符:" + ocInitStr.substringToIndex(5).toJS())
//JS对象
var jsStr = "我是JS对象";
console.log("jsStr 截取前4个字符:" + jsStr.substr(0,4))
}
per
JS中如何使用强转
答:不需要强转,直接当成强转之后的类型使用,JS里面没有类型的概念,都是对象。