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")()
未完,待續......