您的位置:首页 > Web前端 > JavaScript

JSPath基础用法

2016-03-02 17:47 507 查看
1.require
2.调用OC方法
   调用类方法
   调用实例方法
   参数传递
   Property
   方法名转换
3.特殊类型
   Struct
   Selector
   nil
4.NSArray
/ NSString / NSDictionary
5.Block
   block传递
   block
里使用 self 变量
   限制
6.__weak
/ __strong
7.GCD
8.传递
id* 参数
9.常量、宏、全局变量
   常量
   
   全局变量
10.Swift


1. require

在使用Objective-C类之前需要调用 
require('className’)
 :

require('UIView')
var view = UIView.alloc().init()

可以用逗号 
,
 分隔,一次性导入多个类:

require('UIView, UIColor')
var view = UIView.alloc().init()
var red = UIColor.redColor()

或者直接在使用时才调用 
require()
 :

require('UIView').alloc().init()


2. 调用OC方法


调用类方法

var redColor = UIColor.redColor();


调用实例方法

var view = UIView.alloc().init();
view.setNeedsLayout();


参数传递

跟在OC一样传递参数:
var view = UIView.alloc().init();
var superView = UIView.alloc().init()
superView.addSubview(view)


Property

获取/修改 Property 等于调用这个 Property 的 getter / setter 方法,获取时记得加 
()
:
view.setBackgroundColor(redColor);
var bgColor = view.backgroundColor();


方法名转换

多参数方法名使用 
_
 分隔:
var indexPath = require('NSIndexPath').indexPathForRow_inSection(0, 1);

若原 OC 方法名里包含下划线 
_
,在
JS 使用双下划线 
__
 代替:

// Obj-C: [JPObject _privateMethod];
JPObject.__privateMethod()


3. 特殊类型


Struct

JSPatch原生支持 CGRect / CGPoint / CGSize / NSRange 这四个 struct 类型,用 JS 对象表示:
// Obj-C
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(20, 20, 100, 100)];
[view setCenter:CGPointMake(10,10)];
[view sizeThatFits:CGSizeMake(100, 100)];
CGFloat x = view.frame.origin.x;

NSRange range = NSMakeRange(0, 1);


// JS
var view = UIView.alloc().initWithFrame({x:20, y:20, width:100, height:100})
view.setCenter({x: 10, y: 10})
view.sizeThatFits({width: 100, height:100})

var x = view.frame().x
var range = {location: 0, length: 1}

其他 Struct 类型的支持请参照 添加
struct 类型支持


Selector

在JS使用字符串代表 Selector:
//Obj-C
[self performSelector:@selector(viewWillAppear:) withObject:@(YES)];


//JS
self.performSelector_withObject("viewWillAppear:", 1)


nil

JS 上的 
null
 和 
undefined
 都代表
OC 的 
nil
,如果要表示 
NSNull
,
用 
nsnull
 代替:

//Obj-C
@implemention JPTestObject
+ (BOOL)testNull(NSNull *null) {
return [null isKindOfClass:[NSNull class]]
}
@end


//JS
require('JPTestObject').testNull(nsnull) //return 1
require('JPTestObject').testNull(null) //return 0



4. NSArray / NSString / NSDictionary

NSArray / NSString / NSDictionary 不会自动转成对应的JS类型,像普通 NSObject 一样使用它们:

//Obj-C
@implementation JPObject
+ (NSArray *)data
{
return @[[NSMutableString stringWithString:@"JS"]]
}
+ (NSMutableDictionary *)dict
{
return [[NSMutableDictionary alloc] init];
}
@end


// JS
require('JPObject')
var ocStr = JPObject.data().objectAtIndex(0)
ocStr.appendString("Patch")

var dict = JPObject.dict()
dict.setObject_forKey(ocStr, 'name')
console.log(dict.objectForKey('name')) //output: JSPatch


如果要把 NSArray / NSString / NSDictionary 转为对应的 JS 类型,使用 
.toJS()
 接口:

// JS
var data = require('JPObject').data().toJS()
//data instanceof Array === true
data.push("Patch")

var dict = JPObject.dict()
dict.setObject_forKey(data.join(''), 'name')
dict = dict.toJS()
console.log(dict['name'])    //output: JSPatch



5. Block


block 传递

当要把 JS 函数作为 block 参数给 OC时,需要先使用 
block(paramTypes, function)
 接口包装:
// Obj-C
@implementation JPObject
+ (void)request:(void(^)(NSString *content, BOOL success))callback
{
callback(@"I'm content", YES);
}
@end


// JS
require('JPObject').request(block("NSString *, BOOL", function(ctn, succ) {
if (succ) log(ctn)  //output: I'm content
}))

这里 block 里的参数类型用字符串表示,写上这个 block 各个参数的类型,用逗号分隔。NSObject 对象如 
NSString
*
NSArray
*
等可以用 
id
 表示,但
block 对象要用 
NSBlock*
 表示。


OC 返回给 JS 的 block 会自动转为 JS function,直接调用即可:

// Obj-C
@implementation JPObject
typedef void (^JSBlock)(NSDictionary *dict);
+ (JSBlock)genBlock
{
NSString *ctn = @"JSPatch";
JSBlock block = ^(NSDictionary *dict) {
NSLog(@"I'm %@, version: %@", ctn, dict[@"v"])
};
return block;
}
+ (void)execBlock:(JSBlock)blk
{
}
@end


// JS
var blk = require('JPObject').genBlock();
blk({v: "0.0.1"});  //output: I'm JSPatch, version: 0.0.1

若要把这个从 OC 传过来的 block 再传回给 OC,同样需要再用 
block()
 包装,因为这里 
blk
 已经是一个普通的
JS function,跟我们上面定义的 JS function 没有区别:

// JS
var blk = require('JPObject').genBlock();
blk({v: "0.0.1"});  //output: I'm JSPatch, version: 0.0.1
require('JPObject').execBlock(block("id", blk));

总结:JS 没有 block 类型的变量,OC 的 block 对象传到 JS 会变成 JS function,所有要从 JS 传 block 给 OC
都需要用 
block()
 接口包装。


block 里使用 self 变量

在 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();
});
}
}


限制

从 JS 传 block 到 OC,有两个限制:

A. block 参数个数最多支持6个。(若需要支持更多,可以修改源码)

B. block 参数类型不能是 
double

另外不支持 JS 封装的 block 传到 OC 再传回 JS 去调用(原因见 issue
#155):

- (void)callBlock:(void(^)(NSString *str))block {
}

defineClass('JPTestObject', {
run: function() {
self.callBlock(block('NSString*', function(str) {
console.log(str);
}));
},
callBlock: function(blk) {
//blk 这个 block 是上面的 run 函数里 JS 传到 OC 再传过来的,无法调用。
blk("test block");
}
});



6. __weak / __strong

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

例如我们在 OC 里为了避免 block 导致的循环引用,经常这样写:
- (void)test {
__weak id weakSelf = self;
[self setCompleteBlock:^(){
[weakSelf blabla];
}]
}

在 JS 对应的可以这样写:

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

若要在使用 weakSelf 时把它变成 strong 变量,可以用 
__strong()
 接口:

var weakSelf = __weak(self)
self.setCompleteBlock(block(function(){
var storngSelf = __strong(weakSelf)
strongSelf.blabla();
}))


7. GCD

使用 
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
})


8. 传递 
id*
 参数

如果你需要传递 
id*
 参数,像 
NSURLConnection
 里的这个接口里的 
NSError
**
:

+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response

error:(NSError **)error;


这里传入的是一个指向 NSObject 对象的指针,在方法里可以修改这个指针指向的对象,调用后外部可以拿到新指向的对象,对于这样的参数,需要按以下步骤进行传递和获取:
使用 
malloc(sizeof(id))
 创建一个指针

把指针作为参数传给方法

方法调用完,使用 
pval()
 拿到指针新指向的对象

使用完后调用 
releaseTmpObj()
 释放这个对象

使用 
free()
 释放指针

举个例子:
//OC
- (void)testPointer:(NSError **)error {
NSError *err = [[NSError alloc]initWithDomain:@"com.jspatch" code:42 userInfo:nil];
*error = err;
}


//JS
//malloc() pval() free() is provided by JPMemory extension
require('JPEngine').addExtensions(['JPMemory'])

var pError = malloc(sizeof("id"))
self.testPointer(pError)
var error = pval(pError)
if (!error) {
console.log("success")
} else {
console.log(error)
}
releaseTmpObj(pError)
free(pError)


9. 常量、宏、全局变量


常量

Objective-C 里的常量不能直接在 JS 上使用,可以直接在 JS 上用具体值代替,或者在 JS 上重新定义同名的全局变量:
//js
var UIRectEdgeNone   = 0,
UIRectEdgeTop    = 1 << 0,
UIRectEdgeLeft   = 1 << 1,
UIRectEdgeBottom = 1 << 2,
UIRectEdgeRight  = 1 << 3



Objective-C 里的宏同样不能直接在 JS 上使用。若定义的宏是一个值,可以在 JS 定义同样的全局变量代替,若定义的宏是程序,可以在JS展开宏:
#define TABBAR_HEIGHT 40
#define SCREEN_WIDTH [[UIScreen mainScreen] bounds].size.height


//JS
//instead of var tabbarHeight = TABBAR_HEIGHT
var tabbarHeight = 40;
//instead of var width = SCREEN_WIDTH
var width = UIScreen.mainScreen().bounds().height;

若宏的值是某些在底层才能获取到的值,例如 
CGFLOAT_MIN
,可以通过在某个类或实例方法里将它返回,或者用添加扩展的方式提供支持:

@implementation JPMacroSupport
+ (void)main:(JSContext *)context
{
context[@"CGFLOAT_MIN"] = ^CGFloat() {
return CGFLOAT_MIN;
}
}
@end


require('JPEngine').addExtensions(['JPMacroSupport'])
var floatMin = CGFLOAT_MIN();


全局变量

在类里定义的 
static
 全局变量无法在 JS 上获取到,若要在 JS 拿到这个变量,需要在 OC 有类方法或实例方法把它返回:
static NSString *name;
@implementation JPTestObject
+ (NSString *)name {
return name;
}
@end


var name = JPTestObject.name() //拿到全局变量值


10. Swift

使用 
defineClass()
 覆盖
Swift 类时,类名应为 
项目名.原类名
,例如项目
demo 里用 Swift 定义了 ViewController 类,在 JS 覆盖这个类方法时要这样写:

defineClass('demo.ViewController', {})

另外注意:Swift 类需要继承 
NSObject
 才能被调用和替换,若不是继承
NSObject,需要把要类/属性/方法等声明前面加上 
@objc
 修饰符,详见这里

注:OC转JS传送门http://bang590.github.io/JSPatchConvertor/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: