六、Objective-C與JavaScript複雜對象的映射
我們在使用JavaScript調用Objective-C方法的實質是将一個OC函數設定為了JS全局對象的一個屬性,當然我們也可以設定非函數的屬性或者任意JSValue(或者可以轉換為JSValue)的值。例如:
self.jsContext = [[JSContext alloc]init];
//向JS全局對象中添加一個擷取目前Native裝置類型的屬性
[self.jsContext setObject:@"iOS" forKeyedSubscript:@"deviceType"];
但是如果我們想把OC自定義的一個類的對象設定為JS全局對象的某個屬性,JS和OC有着完全不同的對象原理,如果不做任何處理,JS是接收不到OC對象中定義的屬性和方法的。這時就需要使用到前面提到的JSExport協定,需要注意,這個協定不是用來被類遵守的,它裡面沒有規定任何方法,其是用來被繼承定義新的協定的,自定義的協定中約定的方法和屬性可以在JS中被擷取到,示例如下:
OC中建立一個自定義的類:
@protocol MyObjectProtocol <JSExport>
@property(nonatomic,strong)NSString * name;
@property(nonatomic,strong)NSString * subject;
@property(nonatomic,assign)NSInteger age;
-(void)sayHi;
@end
@interface MyObject : NSObject<MyObjectProtocol>
@implementation MyObject
-(void)sayHi{
NSLog(@"Hello JavaScript");
}
添加到JS全局對象中:
MyObject* object = [MyObject new];
object.name = @"Jaki";
object.age = 25;
object.subject = @"OC";
[jsContext setObject:object forKeyedSubscript:@"deviceObject"];
在JS運作環境中可以完整的到deviceObject對象,如下:
七、C語言風格的API解釋
JavaScriptCore架構中除了包含完整的Objective-C和Swift語言的API外,也提供了對C語言的支援。
與JS運作環境相關的方法如下:
//建立一個JSContextRef組
/*
JSContextRef相當于JSContext,同一組中的資料可以共享
*/
JSContextGroupRef JSContextGroupCreate(void);
//記憶體引用
JSContextGroupRef JSContextGroupRetain(JSContextGroupRef group);
//記憶體引用釋放
void JSContextGroupRelease(JSContextGroupRef group);
//建立一個全局的運作環境
JSGlobalContextRef JSGlobalContextCreate(JSClassRef globalObjectClass);
//同上
JSGlobalContextRef JSGlobalContextCreateInGroup(JSContextGroupRef group, JSClassRef globalObjectClass);
JSGlobalContextRef JSGlobalContextRetain(JSGlobalContextRef ctx);
void JSGlobalContextRelease(JSGlobalContextRef ctx);
//擷取全局對象
JSObjectRef JSContextGetGlobalObject(JSContextRef ctx);
//擷取JSContextRef組
JSContextGroupRef JSContextGetGroup(JSContextRef ctx);
//擷取全局的運作環境
JSGlobalContextRef JSContextGetGlobalContext(JSContextRef ctx);
//擷取運作環境名
JSStringRef JSGlobalContextCopyName(JSGlobalContextRef ctx);
//設定運作環境名
void JSGlobalContextSetName(JSGlobalContextRef ctx, JSStringRef name);
與定義JS對象的相關方法如下:
//定義JS類
參數JSClassDefinition是一個結構體 其中可以定義許多回調
JSClassRef JSClassCreate(const JSClassDefinition* definition);
//引用記憶體
JSClassRef JSClassRetain(JSClassRef jsClass);
//釋放記憶體
void JSClassRelease(JSClassRef jsClass);
//建立一個JS對象
JSObjectRef JSObjectMake(JSContextRef ctx, JSClassRef jsClass, void* data);
//定義JS函數
JSObjectRef JSObjectMakeFunctionWithCallback(JSContextRef ctx, JSStringRef name, JSObjectCallAsFunctionCallback callAsFunction);
//定義構造函數
JSObjectRef JSObjectMakeConstructor(JSContextRef ctx, JSClassRef jsClass, JSObjectCallAsConstructorCallback callAsConstructor);
//定義數組
JSObjectRef JSObjectMakeArray(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
//定義日期對象
JSObjectRef JSObjectMakeDate(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
//定義異常對象
JSObjectRef JSObjectMakeError(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
//定義正則對象
JSObjectRef JSObjectMakeRegExp(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
//定義函數對象
JSObjectRef JSObjectMakeFunction(JSContextRef ctx, JSStringRef name, unsigned parameterCount, const JSStringRef parameterNames[], JSStringRef body, JSStringRef sourceURL, int startingLineNumber, JSValueRef* exception);
//擷取對象的屬性
JSValueRef JSObjectGetPrototype(JSContextRef ctx, JSObjectRef object);
//設定對象的屬性
void JSObjectSetPrototype(JSContextRef ctx, JSObjectRef object, JSValueRef value);
//檢查對象是否包含某個屬性
bool JSObjectHasProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName);
//擷取對象屬性
JSValueRef JSObjectGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception);
//定義對象屬性
void JSObjectSetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSPropertyAttributes attributes, JSValueRef* exception);
//删除對象屬性
bool JSObjectDeleteProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception);
//擷取數組值
JSValueRef JSObjectGetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsigned propertyIndex, JSValueRef* exception);
//設定數組值
void JSObjectSetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsigned propertyIndex, JSValueRef value, JSValueRef* exception);
//擷取私有資料
void* JSObjectGetPrivate(JSObjectRef object);
//設定私有資料
bool JSObjectSetPrivate(JSObjectRef object, void* data);
//判斷是否為函數
bool JSObjectIsFunction(JSContextRef ctx, JSObjectRef object);
//将對象作為函數來調用
JSValueRef JSObjectCallAsFunction(JSContextRef ctx, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
//判斷是否為構造函數
bool JSObjectIsConstructor(JSContextRef ctx, JSObjectRef object);
//将對象作為構造函數來調用
JSObjectRef JSObjectCallAsConstructor(JSContextRef ctx, JSObjectRef object, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
//擷取所有屬性名
JSPropertyNameArrayRef JSObjectCopyPropertyNames(JSContextRef ctx, JSObjectRef object);
//進行記憶體引用
JSPropertyNameArrayRef JSPropertyNameArrayRetain(JSPropertyNameArrayRef array);
//記憶體釋放
void JSPropertyNameArrayRelease(JSPropertyNameArrayRef array);
//擷取屬性個數
size_t JSPropertyNameArrayGetCount(JSPropertyNameArrayRef array);
//在屬性名數組中取值
JSStringRef JSPropertyNameArrayGetNameAtIndex(JSPropertyNameArrayRef array, size_t index);
//添加屬性名
void JSPropertyNameAccumulatorAddName(JSPropertyNameAccumulatorRef accumulator, JSStringRef propertyName);
JS資料類型相關定義在JSValueRef中,如下:
//擷取值的類型
枚舉如下:
typedef enum {
kJSTypeUndefined,
kJSTypeNull,
kJSTypeBoolean,
kJSTypeNumber,
kJSTypeString,
kJSTypeObject
} JSType;
JSType JSValueGetType(JSContextRef ctx, JSValueRef);
//判斷是否為undefined類型
bool JSValueIsUndefined(JSContextRef ctx, JSValueRef value);
//判斷是否為null類型
bool JSValueIsNull(JSContextRef ctx, JSValueRef value);
//判斷是否為布爾類型
bool JSValueIsBoolean(JSContextRef ctx, JSValueRef value);
//判斷是否為數值類型
bool JSValueIsNumber(JSContextRef ctx, JSValueRef value);
//判斷是否為字元串類型
bool JSValueIsString(JSContextRef ctx, JSValueRef value);
//判斷是否為對象類型
bool JSValueIsObject(JSContextRef ctx, JSValueRef value);
//是否是類
bool JSValueIsObjectOfClass(JSContextRef ctx, JSValueRef value, JSClassRef jsClass);
//是否是數組
bool JSValueIsArray(JSContextRef ctx, JSValueRef value);
//是否是日期
bool JSValueIsDate(JSContextRef ctx, JSValueRef value);
//比較值是否相等
bool JSValueIsEqual(JSContextRef ctx, JSValueRef a, JSValueRef b, JSValueRef* exception);
//比較值是否全等
bool JSValueIsStrictEqual(JSContextRef ctx, JSValueRef a, JSValueRef b);
//是否是某個類的執行個體
bool JSValueIsInstanceOfConstructor(JSContextRef ctx, JSValueRef value, JSObjectRef constructor, JSValueRef* exception);
//建立undefined值
JSValueRef JSValueMakeUndefined(JSContextRef ctx);
//建立null值
JSValueRef JSValueMakeNull(JSContextRef ctx);
//建立布爾值
JSValueRef JSValueMakeBoolean(JSContextRef ctx, bool boolean);
//建立數值
JSValueRef JSValueMakeNumber(JSContextRef ctx, double number);
//建立字元串值
JSValueRef JSValueMakeString(JSContextRef ctx, JSStringRef string);
//通過JSON建立對象
JSValueRef JSValueMakeFromJSONString(JSContextRef ctx, JSStringRef string);
//将對象轉為JSON字元串
JSStringRef JSValueCreateJSONString(JSContextRef ctx, JSValueRef value, unsigned indent, JSValueRef* exception);
//進行布爾值轉換
bool JSValueToBoolean(JSContextRef ctx, JSValueRef value);
//進行數值轉換
double JSValueToNumber(JSContextRef ctx, JSValueRef value, JSValueRef* exception);
//字元串值指派
JSStringRef JSValueToStringCopy(JSContextRef ctx, JSValueRef value, JSValueRef* exception);
//值與對象的轉換
JSObjectRef JSValueToObject(JSContextRef ctx, JSValueRef value, JSValueRef* exception);
在C風格的API中,字元串也被包裝成了JSStringRef類型,其中方法如下:
//建立js字元串
JSStringRef JSStringCreateWithCharacters(const JSChar* chars, size_t numChars);
JSStringRef JSStringCreateWithUTF8CString(const char* string);
//記憶體引用于釋放
JSStringRef JSStringRetain(JSStringRef string);
void JSStringRelease(JSStringRef string);
//擷取字元串長度
size_t JSStringGetLength(JSStringRef string);
//轉成UTF8字元串
size_t JSStringGetUTF8CString(JSStringRef string, char* buffer, size_t bufferSize);
//字元串比較
bool JSStringIsEqual(JSStringRef a, JSStringRef b);
bool JSStringIsEqualToUTF8CString(JSStringRef a, const char* b);