JSPatch 常见问题

字符串 / 数组 / 字典 操作问题

刚使用 JSPatch 经常会对 NSString / NSArray / NSDictionary / NSDate 这四个类的使用感到迷惑,因为 JS 语言本身有对应的这四个类型,会跟 OC 的这四个类混淆。要避免混淆,要弄清楚两点:

1.需要认清这四个类有 JS 跟 OC 两种类型

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

var ocStr = JPTestObject.name();
var ocInfo = JPTestObject.info();
var ocUsers = JPTestObject.users();

//以上三个是从 OC 返回的 OC 对象,可以调用 OC 方法:
ocStr.rangeOfString("I'm");   //OK
ocInfo.addObject_forKey("a", "b");   //OK
ocUsers.firstObject();    //OK

///

var str = "I'm JS String";
var info = @{"k": "v"};
var users = ["alex", "bang", "cat"];

//以上三个是 JS 对象,不能调用 OC 方法:
str.rangeOfString("I'm");   //crash
str.addObject_forKey("a", "b");   //crash
str.firstObject();    //crash

2.若要用JS语法操作这些类型,要确保它是 JS 对象。

//错误:ocStr 不是 JS 对象,不能用 JS 语法拼接字符串
var newStr = ocStr + "js string";   

//正确:已用 .toJS() 接口转为 JS 对象,可以用 JS语法操作
var transStr = ocStr.toJS();
var newStr = transStr + "js string";  


//错误:ocUsers 不是 JS 对象,不能用[]语法,也不能用 JS 语法遍历
var firstUser = ocUser[0];
for (var i = 0; i < ocUsers.length; i ++) {
  var user = ocUsers[i];
}


//正确:已用 .toJS() 接口转为 JS 对象,可以用 JS语法操作
var transArr = ocUsers.toJS();
var firstUser = ocUser[0];
for (var i = 0; i < transArr.length; i ++) {
  var user = transArr[i];
}

stringWithFormat

在 JSPatch 不支持调用 [NSString stringWithFormat:@""] 方法,原因是这是参数个数可变方法,JSPatch 原理是通过 NSInvocation 动态调用方法,而 NSInvocation 不支持可变参数,参见官方文档

若需要拼接字符串,请把 NSString 对象全转为 JS String 后在 JS 语法下拼接。另外在 JS 语法下数字也可以直接用运算符拼接:

OC:
NSString *ret = [NSString stringWithFormat:@"name:%@ age:(%d)", @"alex", @"12"];

JS:
var ret = "name:" + "alex" + " age:(" + 12 + ")";

NSNumber 相关问题

NSNumber 与上述四个类型 不一样 ,所有数值类型以及 NSNumber 对象到 JS 后都会变成数值,不能再调用这个数值的任何方法:

//OC
@implementation JPTestObject
+ (NSNumber *)returnNSNumber {
    return @(42);
}
+ (int)returnInt
{
  return 42;
}
@end

var numFromOC = JPTestObject.returnNumber()
var intFromOC = JPTestObject.returnInt()
var jsNum = 42

//以上三个变量是相等的:
console.log(numFromOC == intFromOC == jsNum) //true

//不能调用 NSNumber 方法:
numFromOC.isEqualToNumber(42);  //crash

//所有数值操作都应该在 JS 语法下操作:
parseInt(numFromOC);
var all = numFromOC + intFromOC + jsNum;

for...in

首先从 OC 返回的 NSArray / NSDictionary 对象是不能直接用 for...in 遍历的,需要调用 .toJS()后才能进行遍历,详情见上文。

然后在遍历数组时,JavaScript 的 for...in 语法定义与 Objective-C 不同:

//OC
NSArray *arr = @[@"name", @"age"];
for (var o in arr) {
  NSLog(@"%@", o); //输出 name age
}

var arr = ["name", "age"];
for (var o in arr) {
  console.log(o); //输出 0, 1,表示遍历数组的序号
  console.log(arr[o]); //输出 name age,这样才表示数组的值
}

block 相关问题

若使用 block 时出现 crash,最常见的原因是在 block 里使用了 self 变量,应该在 JS 声明另一个变量持有 self,详情见这里

另外请详读 block 的传递规则,以及使用 block 的几个限制

内存释放问题

如果一个 OC 对象被 JS 引用,或者在 JS 创建这个对象,这个 OC 对象在退出作用域后不会马上释放,而是会等到 JS 垃圾回收时才释放,这会导致一些 OC 对象延迟释放:

defineClass('JPTestObject', {
  testObj: function() {
    var view = UIView.alloc().init();
    //函数执行完退出作用域,或者手动把这个变量置为null,这个 OC 对象都不会立即释放
    //在 JS 没有变量持有这些对象后,JS 引擎会在垃圾回收时才释放
    view = null;
  }
});
没有被 JS 引用过的 OC 对象不受影响。更多讨论见  #69

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值