一个对象在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