一个对象在JS和OC之间传递的时候会有个对应的类型转换,在JSValue.h源码中有个简单的介绍:
@textblock
Objective-C type | JavaScript type
--------------------+---------------------
nil | undefined
NSNull | null
NSString | string
NSNumber | number, boolean
NSDictionary | Object object
NSArray | Array object
NSDate | Date object
NSBlock (1) | Function object (1)
id (2) | Wrapper object (2)
Class (3) | Constructor object (3)
@/textblock
这里重点提一下OC 的 id类型到JS环境后会是Wrapper object,在IOS7 及以下的系统中这个Wrapper object在被访问的时候会引起崩溃异常,这个坑很深,困扰了好几天才想到比较好的解决办法,将id类型封装到NSDictionary内部返回的,详细的情况在[原理部分]()会进行介绍。Native的方法在被执行的时候参数来源有两种,第一种:从OC传给JS,再从JS回传给OC,这种参数是不需要进行类型转换可以直接使用的;第二种:直接在JS生成,简单的类型如:Array、Dictionary、Data会在传递过程中自动转换,复杂的类型:如 CGRect、UIColor以及自定义的数据类型是无法自动转换的就需要手动封装。
1:现有的数据类型封装
CGRect
CGPoint
CGSize
UIColor
UIFont
……
2:如何封装数据
JS生成自定义对象都是Dictionary的实例,其中有个className字段代表到OC中想要被转换成的类型,JS的封装如下:
var NJCSCGPoint_JS = {
create:function(x, y){
var CGPoint = NJCSStruct_JS.create("{CGPoint=dd}");
CGPoint.x = x;
CGPoint.y = y;
return CGPoint;
}
}
var NJCSCGSize_JS = {
create:function(width, height){
var CGSize = NJCSStruct_JS.create("{CGSize=dd}");
CGSize.width = width;
CGSize.height = height;
return CGSize;
}
}
var NJCSCGRect = {
create:function(x, y, width, height){
var CGRect = NJCSStruct_JS.create("{CGRect={CGPoint=dd}{CGSize=dd}}");
CGRect.x = x;
CGRect.y = y;
CGRect.width = width;
CGRect.height = height;
return CGRect;
}
}
与之对应的OC封装如下,以UIFont为例:
模型转换协议:
#import@protocol NJCSModelTypeAdapterProtocol - (id)OCModel2JSModel:(id)ocModel; - (id)JSModel2OCModel:(id)jsModel; @end
.h文件:
#import#import "NJCSModelTypeAdapterProtocol.h" @interface UIFontModelAdapter : NSObject @end
.m文件:
#import "UIFontModelAdapter.h" #import@implementation UIFontModelAdapter - (id)OCModel2JSModelWith:(void *)value { UIFont *font = (__bridge UIFont *)value; UIFontDescriptor *fontDes = font.fontDescriptor; NSNumber *fontSize = [fontDes objectForKey:@"NSFontSizeAttribute"]; NSString *fontName = [fontDes objectForKey:@"NSFontNameAttribute"]; return @{@"fontSize":fontSize, @"fontName":fontName}; } - (id)OCModel2JSModel:(id)ocModel { UIFont *font = (UIFont *)ocModel; NSNumber *fontSize = [NSNumber numberWithFloat:[font pointSize]]; return fontSize; } - (id)JSModel2OCModel:(id)jsModel { NSParameterAssert(jsModel); float fontSize = 12.0f; if ([jsModel isKindOfClass:[NSDictionary class]]) { NSNumber *fontSizeNumber = [jsModel objectForKey:@"fontSize"]; fontSize = [fontSizeNumber floatValue]; NSString *fontName = [jsModel objectForKey:@"fontName"]; if(fontName && ![fontName isEqualToString:@""]){ return [UIFont fontWithName:fontName size:fontSize]; } } return [UIFont systemFontOfSize:fontSize]; } @end