1.字符串/数组/字典操作问题#
刚使用 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
info.addObject_forKey("a", "b"); //crash
users.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 = transArr[0];
for (var i = 0; i < transArr.length; i ++) {
var user = transArr[i];
}
//错误: ocInfo 不是 JS 对象,不能用[]语法
var v = ocInfo['k'];
//正确:已用 .toJS() 接口转为 JS 对象,可以用 JS语法操作
var transDict = ocInfo.toJS();
var v = transDict['k'];
stringWithFormat#
JSPatch 支持调用 stringWithFormat,不过所有参数类型都需改为 %@:
//OC
[NSString stringWithFormat:@"name:%@, age:%d", @"alex", 12];
//JS
NSString.stringWithFormat("name:%@, age:%@", "alex", 12);
虽然支持 stringWithFormat,但还是建议使用 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
defineClass("JPViewController", {
viewDidLoad: function() {
var slf = self;
require("JPTestObject").callBlock(block(function(){
//`self` is not available here, use `slf` instead.
slf.doSomething();
});
}
}
Property和私有成员变量#
获取/修改 Property 等于调用这个 Property 的 getter / setter 方法,获取时记得加 ():
view.setBackgroundColor(redColor);
var bgColor = view.backgroundColor();
使用 valueForKey() 和 setValue_forKey() 获取/修改私有成员变量:
// OC
@implementation JPTableViewController {
NSArray *_data;
}
@end
// JS
defineClass("JPTableViewController", {
viewDidLoad: function() {
var data = self.valueForKey("_data") //get member variables
self.setValue_forKey(["JSPatch"], "_data") //set member variables
},
})
调试#
可以使用 console.log()打印一个对象,作用相当于 NSLog(),会直接在 XCode 控制台打出。
var view = UIView.alloc().init();
var str = "test";
var num = 1;
console.log(view, str, num)
console.log(str + num); //直接在JS拼接字符串
也可以通过 Safari 的调试工具对 JS 进行断点调试,详见 JS 断点调试
例如可以在控制台打印OC对象 :
url.__c("toJS")()
未完,待续......