JSPatch文档整理(三)

四.Jspatch 使用:

(一)基础用法:(见文档 2.22.3)
jspatch 作为对 oc 类与类接口的补充完善,其中的 js oc 间的通信总结而言大体分为以下几类:
1. js oc 类中定义的方法进行重写(类方法、对象方法、Category 方法)

  1. js 调用 oc 方法(类方法、对象方法),对其进行参数传递,以及接收调用结构

  2. js 使用(读、写)oc 属性、私有成员变量

  3. js oc 类新增方法(类方法、对象方法、遵守的协议方法)

  4. js oc 新增类等(oc 类(使用 defineclass 接口)、js 类(使用 defineJSClass

    接口)

Jspatch 的基础用法以及与 oc 间的接口对应、通信等见文档 2.2。此处只说使用中的注意事项。

1. js 数据类型与 oc 数据类型的对应
js 中,一切数据类型均为对象。根据 js oc 中数据类型的区别分为六类进行讨论:
1) NSString / NSArray / NSDictionary / NSDate 类型:

对于 oc 中的 NSString / NSArray / NSDictionary / NSDate 四种类型,JS 语言本身有对应的这四个类型,在使用过程中,如参数传递、调用接口返回接口等使用中会产生混淆。

A.

B.

C.

js 调用 oc 接口:
a.参数传递:此种情况,可以为其传 oc 数据类型,亦可以传 js 相应的类型,传递过程中,会自动转化为相应的 oc 类型b.接口返回:返回的均为 oc 对象,此时返回的对象只能调用 oc 中的方法,若要调用 js 中相应类型的方法,需先将其转换为 js 类型(调用toJS()接口)
重写
oc 接口:

a.参数:此时重写的 oc 接口可能会在 oc 中调用,也可能会在 js 中调用,此时的参数类型保持为 oc 中原有接口的类型,因此在方法实现中只能调用对应的 oc 接口。
b.接口返回:同上

新增 js 接口:
a.参数:新增的 js 接口一般情况下只会在 js 中调用,因此其参数类型可以为 js 类型亦可以为 oc 类型,只是要保持调用时传递的参数与接口内部实现时的类型一致。
b.接口返回:同上

2) oc 中的其它对象类型:由于 js 中没有相应的数据类型相对应,因此产生的均为 oc 类型,不存在混淆的情况。

3)非 id 数据类型的使用(如 intfloatNSIntegerstruct oc 中的非对象类型)

A. 对于 js 调用 oc 接口、重写 oc 接口等情况,由于 jspatch 中已经存在相应的类型转换机制,因此可以直接传递使用 oc 中相应的数据类型。

B. 对于新增 js 接口:
a.一般新增接口,此类接口在 oc 中没有声明也没有定义,只在 js

新增,因此一般只会在 js 中调用,因此不存在 oc 中的非 id 数据类型的传递。b. 对于只在 oc 中声明,但却没有在 oc 中定义的方法,此时若在 oc

中调用,会产生崩溃,因此需在js中为其实现。要用 JSPatch 修复这样的 bug

就需要 JSPatch 可以动态添加指定参数类型的方法。对此可以用defineProtocol() 接口定义参数类型,再在 defineClass() 中实现,就可以动态添加指定参数类型的方法了。(此处测试的情况是:defineProtocol ios8 中运行会崩溃,ios9ios10 可以运行)defineProtocol 的具体用法见文档 2.3 中的defineProtocol 使用文档一文,以及文档 2.11
4
)struct 数据类型:

(此处为在 js 中使用 struct 类型,需要与 3)中的新增接口中有 struct 参数情况作区分)(见文档 2.3 中的添加 struct 类型支持一文):

JSPatch 默认支持的 struct 类型只有 CGRect / CGPoint / CGSize / NSRange,若要让 JS 脚本支持其他 struct 类型,需要先手动注册。例如要支持CGAffineTransform,需要在使用前在 JS 使用 defineStruct() 接口定义:require('JPEngine').defineStruct({

"name": "CGAffineTransform","types": "FFFFFF",
"keys": ["a", "b", "c", "d", "tx", "ty"]

})
6
) 传递 id* 参数:(见文档 2.3 中的JSPatch 基础用法JPMemory 使用

文档)
7) 常量、枚举、宏、全局变量的使用:(见文档 2.3 中的JSPatch 基础用法)8) autoConvertOCType()的使用:

JSPatch NSDictionary / NSArray / NSString / NSDate 这几个类型从 OC传递到 JS 时不会自动转为 JS 对应的 Object / Array / String / Date 类型,而是当成一个普通的 OC 对象,于是在 JS 端这些类型就存在两种对象,一种 OC 对象一种 JS 原生对象,详见这里。在开发功能模块时这点会造成较大困扰,于是建议在开头执行:autoConvertOCType(1);
这样所有 NSDictionary / NSArray / NSString / NSDate 返回到 JS 时会自动转为 JS 对应类型,JS 上只有一种类型,同时也不能再调用这些类型的
OC 方法

2. js oc block 的使用:(见文档 2.3 中的JSPatch 基础用法一文)1) 应用类型主要分为三种情况:

A. js oc 传递 block 参数:
a. oc中方法request参数为block类型

- (void)request:(void(^)(UIView *argView, BOOL success))callback{

_didRequestBlock = [callback copy];}

b.js:在js中调用上述request方法,并向其传递block参数self.request(block("UIView *, BOOL", function(ctn, succ) {

if (succ)
console.log("-zheshiceshfi sdfjsd");

if (ctn) {weakSelf.view().addSubview(ctn);

}

}));

// weakSelf.view().addSubview(ctn);

//output: I'm content

c. 此处当要把 JS 函数作为 block 参数给 OC时,需要先使用block(paramTypes, function) 接口包装,这里 block 里的参数类型用字符串表示,写上这个 block 各个参数的类型,用逗号分隔。NSObject 对象如 NSString *,NSArray *等可以用 id 表示,但 block 对象要用 NSBlock* 表示。

B.重写上述oc中的接受block参数的接口:Js代码:

request: function(blk) {
var view = UIView.alloc().initWithFrame({x:200, y:100, width:100,

height:20});

view.setBackgroundColor(UIColor.blackColor());blk(view,true); },

C.不支持 JS 封装的 block 传到 OC 再传回 JS 去调用:具体情况为,在js中重写了c中的接受block参数的接口(上述B步骤),同时jsoc传递block参数(上述A步骤),此时会崩溃。

2) 其它细节问题
a. block 里无法使用 self 变量,需要在进入 block 之前使用临时变

量保存它:
defineClass("JPViewController", {

viewDidLoad: function() {
var slf = self;require("JPTestObject").callBlock(block(function(){//`self` is not available here, use `slf` instead.slf.doSomething();

});}

}

d. block 参数个数最多支持6个。(若需要支持更多,可以修改源码)e. block 参数类型不能是 double / NSBlock / struct 类型

c. 可以在 JS 通过 __weak() 声明一个 weak 变量,主要用于避免循环引用。

var weakSelf = __weak(self)self.setCompleteBlock(block(function(){

weakSelf.blabla();}))

3. 多线程的运用:1) 接口对应:

使用 dispatch_after() dispatch_async_main() dispatch_sync_main()dispatch_async_global_queue() 接口调用GCD方法:
// Obj-C
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)),dispatch_get_main_queue(), ^{

// do something});

dispatch_async(dispatch_get_main_queue(), ^{// do something

});
// JS
dispatch_after(1.0, function(){

// do something})

dispatch_async_main(function(){// do something

})dispatch_sync_main(function(){

// do something})

dispatch_async_global_queue(function(){// do something

})

2) performSelectorInOC 使用文档(见文档 2.3 performSelectorInOC 使用文档一文):

JavaScript 语言是单线程的,在 OC 使用 JavaScriptCore 引擎执行 JS代码时,会对 JS 代码块加锁,保证同个 JSContext 下的 JS 代码都是顺序执行。所以使用 JSPatch 替换的方法都会在这个锁里执行,无法并行执行,这导致如果主线程和子线程同时运行了 JSPatch 替换的方法,子线程就会卡住主线程。

对此可以使用 .performSelectorInOC(selector, arguments, callback) 方法,在 JS 使用这个接口调用 OC 方法时,可以脱离 JavaScriptCore 的锁,在释放了 JavaScriptCore 锁后才在 OC 执行这个方法,这样这个方法就可以与其他线程的 JS 方法并行执行。

(二) 加载动态库
对于
iOS 内置的动态库,若原 APP 里没有加载,可以通过以下方式动态加

载,以加载 SafariServices.framework 为例:

var bundle =NSBundle.bundleWithPath("/System/Library/Frameworks/SafariServices.framework");
bundle.load();

加载后就可以使用 SafariServices.framework

(三)其它扩展:
1)JPCleaner:(见文档 2.3 “JPCleaner 即时撤回脚本一文)

如果想在 JSPatch 脚本执行后撤回脚本,可以通过扩展 JPCleaner 做到。只需引入 JPCleaner.h,调用 +cleanAll 接口就可以把当前所有被 JSPatch 替换的方法恢复原样。另外还有 +cleanClass: 接口支持只回退某个类。这些接口可以在OC 调用,也可以在 JS 脚本动态调用:

OC 中调用:
[JPCleaner cleanAll]
[JPCleaner cleanClass:@"JPViewController"];

也可以在 JS 中调用:require('JPCleaner').cleanAll();

3) JPNumber(见文档 2.3 “JPNumber 使用文档一文)NSNumberJS里都变成了数值,不能调用NSNumber的方法,JPNumber

提供了在NSNumberJS中使用的方法。
a.JPNumber.h / JPNumber.m 加入项目
b.JS 脚本使用前调用 require('JPEngine').addExtensions(['JPNumber'])
c. toOCNumber: js
数字转 NSNumber
d.toJSNumber: NSNumber
转回js数字:
e. OCNumber: 通过OCNumber的调用得到OCNSNumber或者NSNumber

的子类,参数里填写类型,类方法和类方法的参数数组4) JPCFunction:(见文档 2.3 “C 函数调用一文)

  1. 接入扩展 Extensions/JPCFunction 后,可以调用项目中任意非内联 C函数。

  2. Extensions/JPCFunction 加入项目。

  3. JS 脚本加载这个扩展。

    require('JPEngine').addExtensions(['JPCFunction'])

  4. 对于要调用的 C 函数,先定义它的参数类型。

    defineCFunction("malloc", "void *, size_t")

    defineCFunction("NSClassFromString", "Class, NSString *"

e. 然后就可以调用这些 C 函数了。

malloc(10)NSClassFromString("UIView")

(四)调试 js 代码:(见文档 2.3 “JPCleaner 即时撤回脚本一文 JS 断点调试) 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值