Skip to content

使用 JSPatch 开发功能模块

bang edited this page Mar 29, 2017 · 2 revisions

JSPatch 可以用于开发功能模块,把一部分业务完全用 JS 开发,再动态下发给客户端执行,让 APP 同时拥有原生体验和动态特性,并且可以沿用 OC 的思维,使用所有 OC 库以及 JS 工具库进行开发。

使用 JSPatch 开发功能模块有一些新接口建议使用:

autoConvertOCType()

JSPatch 对 NSDictionary / NSArray / NSString / NSDate 这几个类型从 OC 传递到 JS 时不会自动转为 JS 对应的 Object / Array / String / Date 类型,而是当成一个普通的 OC 对象,于是在 JS 端这些类型就存在两种对象,一种 OC 对象一种 JS 原生对象,详见[这里](https://github.com/bang590/JSPatch/wiki/JSPatch-常见问题#字符串 / 数组 / 字典 操作问题)。

在开发功能模块时这点会造成较大困扰,于是建议在开头执行:

autoConvertOCType(1);

这样所有 NSDictionary / NSArray / NSString / NSDate 返回到 JS 时会自动转为 JS 对应类型,JS 上只有一种类型,同时也不能再调用这些类型的 OC 方法:

//OC
@implementation JPTestObject
+ (NSMutableDictionary *)info {
  return @{@"k": @"v"};
}
+ (NSArray *)users {
  return @[@"alex", @"bang", @"cat"];
}
@end
autoConvertOCType(1);

var info = JPTestObject.info();
var users = JPTestObject.users();

//info/users 是 js 类型,直接用JS语法操作:
console.log(info['k']); 
console.log(users[0]);

//调用它们的 OC 方法是不允许的:
info.objectForKey('k');   //crash
users.objectAtIndex(1);   //crash


//若临时必须调用这些对象的 OC 方法,可以先关闭再开启自动转换:
autoConvertOCType(0);

var ocInfo = JPTestObject.info();
console.log(ocInfo.objectForKey('k'))    //OK

autoConvertOCType(1);

defineJSClass()

开发功能时会创建很多类,有些是需要继承自 OC 类的,例如 VC 层需要继承 UIView 和 UIViewController,有些是不需要继承 OC 类的,例如 M 层用于数据操作的类。在 JS 创建这些类实际上不需要跟 OC 发生关系,建议使用 defineJSClass() 定义这些类,性能上会有很大提升。

示例:

defineJSClass('JPBaseDataSource', {
  init: function() {
    this.baseData = [1,2,3];
  }
});
var _dataSourceShareInstance;

defineJSClass('JPDataSource : JPBaseDataSource', {
  init: function(){
    this.super().init();
    this.data = this.baseData.concat([4,5,6]);
    return this;
  },

  readDataAtIndex: function(i) {
    return this.data[i]
  },

}, {
  shareInstance: function(){
    if (!_dataSourceShareInstance) {
      _dataSourceShareInstance = JPDataSource.alloc().init();
    }
    return _dataSourceShareInstance;
  },
})
var dataSource = JPDataSource.shareInstance();
dataSource.readDataAtIndex(1)

可以看到 defineJSClass() 的使用方式跟 defineClass() 几乎一样,方法定义 / 对象生成 / 实例方法和类方法定义 / 继承的写法 / super的写法 都是一样的,只有两点不同:

  1. 用 this 关键字代替 self
  2. property 不用 getter/setter,直接存取。

include() / resourcePath()

可以用 include() 接口引入其他 js 文件,路径为执行的主程序所在目录的相对路径,例如:

 - js
  - main.js
  - JPDataSource.js
  - controllers
    - JPViewController.js
  - views
    - JPView.js
  - img
    - demo.png

main.js 为主程序 (传入 [JPEngine evaluateScriptWithPath:@""] 执行),main.js 所在目录就是根目录,include 时填相对这个目录的路径:

//main.js
include('JPDataSource.js');
include('controllers/JPViewController.js');
//JPViewController.js
include('views/JPView.js');

此外可以通过 resourcePath() 获取资源文件的实际路径,路径规则与 include() 一样:

//JPView.js
var path = resourcePath('img/demo.png');
var image = require('UIImage').imageWithContentsOfFile(path);

其他

defineClass() 创建的方法如果确定不会在 OC 调用到 (不是 protocol / target action 方法),也不会被使用者调用,完全是私有方法,建议以下划线 _ 开头命名,这样可以减少不必要的 OC 方法注册。

Demo

其他写法可以参考 Dribbble Demo

Clone this wiki locally