JSExportAlthough the comments in the Code are also described in detail, the code is more convincing for programmers, for example, the same figure is the top ten thousand words. This article first describes the JSContext and JSValue which are relatively easy to understand but commonly used, as well as the usage and effects of these methods.
JSContext and JSValueJSVirtualMachine
Provides underlying resources for JavaScript operations,JSContext
It provides a runtime environment for it.- (JSValue *)evaluateScript:(NSString *)script;
Method to execute a JavaScript script, and if there are methods, variables and other information in it will be stored for use as needed. JSContext is created based onJSVirtualMachine
:- (id)initWithVirtualMachine:(JSVirtualMachine *)virtualMachine;
.- (id)init;
Then, a newJSVirtualMachine
Object and then call the initialization method of the front.
JSValue
It can be said that it is a bridge between JavaScript and Object-C. It provides a variety of methods to easily convert JavaScript data types into Objective-C, or convert the past. The following table shows the one-to-one matching method:
Objective-C |
JavaScript |
JSValue Convert |
JSValue Constructor |
Nil |
Undefined |
|
ValueWithUndefinedInContext |
NSNull |
Null |
|
ValueWithNullInContext: |
NSString |
String |
ToString |
|
NSNumber |
Number, boolean |
ToNumber ToBool ToDouble ToInt32 ToUInt32 |
ValueWithBool: inContext: ValueWithDouble: inContext: ValueWithInt32: inContext: ValueWithUInt32: inContext: |
NSDictionary |
Object |
ToDictionary |
ValueWithNewObjectInContext: |
NSArray |
Array object |
ToArray |
ValueWithNewArrayInContext: |
NSDate |
Date object |
ToDate |
|
NSBlock |
Function object |
|
|
Id |
Wrapper object |
ToObject ToObjectOfClass: |
ValueWithObject: inContext: |
Class |
Constructor object |
|
|
Basic type conversionLet's take a look at a simple example:
1 JSContext *context = [[JSContext alloc] init];2 JSValue *jsVal = [context evaluateScript:@"21+7"];3 int iVal = [jsVal toInt32];4 NSLog(@"JSValue: %@, int: %d", jsVal, iVal);5 6 //Output:7 // JSValue: 28, int: 28
You can also save a JavaScript variable inJSContext
And obtain it by subscript. ForArray
OrObject
Type,JSValue
You can also directly set values and assign values by subscript.
1 JSContext *context = [[JSContext alloc] init]; 2 [context evaluateScript:@"var arr = [21, 7 , 'iderzheng.com'];"]; 3 JSValue *jsArr = context[@"arr"]; // Get array from JSContext 4 5 NSLog(@"JS Array: %@; Length: %@", jsArr, jsArr[@"length"]); 6 jsArr[1] = @"blog"; // Use JSValue as array 7 jsArr[7] = @7; 8 9 NSLog(@"JS Array: %@; Length: %d", jsArr, [jsArr[@"length"] toInt32]);10 11 NSArray *nsArr = [jsArr toArray];12 NSLog(@"NSArray: %@", nsArr);13 14 //Output:15 // JS Array: 21,7,iderzheng.com Length: 316 // JS Array: 21,blog,iderzheng.com,,,,,7 Length: 817 // NSArray: (18 // 21,19 // blog,20 // "iderzheng.com",21 // "
",22 // "
",23 // "
",24 // "
",25 // 726 // )
The output results show that the Code successfully assigns data from Objective-C to the JavaScript array, andJSValue
It follows the array feature of JavaScript: the array size is automatically extended without subscript offside. And passJSValue
You can also obtain attributes on JavaScript objects. For example"length"
The length of the JavaScript array is obtained. ConvertNSArray
All the information is correctly converted.
Method ConversionVarious data types can be converted. The Objective-C Block can also be passed into JSContext for use as JavaScript. For examplelog
Method. Although JavaScritpCore does not come with it (after all, it does not run on a webpage, but naturally does not have windows, document, and console classes), you can define a Block method to call NSLog for simulation:
1 JSContext *context = [[JSContext alloc] init]; 2 context[@"log"] = ^() { 3 NSLog(@"+++++++Begin Log+++++++"); 4 5 NSArray *args = [JSContext currentArguments]; 6 for (JSValue *jsVal in args) { 7 NSLog(@"%@", jsVal); 8 } 9 10 JSValue *this = [JSContext currentThis];11 NSLog(@"this: %@",this);12 NSLog(@"-------End Log-------");13 };14 15 [context evaluateScript:@"log('ider', [7, 21], { hello:'world', js:100 });"];16 17 //Output:18 // +++++++Begin Log+++++++19 // ider20 // 7,2121 // [object Object]22 // this: [object GlobalObject]23 // -------End Log-------
If a Block is successfully called in JavaScript, the method returns to Objective-C, and still follows various features of the JavaScript method. For example, the method parameters are not fixed. Because of this,JSContext
Provides a class method to obtain the parameter list (+ (JSContext *)currentContext;
) And the object currently calling this method (+ (JSValue *)currentThis
). For"this"
, The output content isGlobalObject
, This is alsoJSContext
Object Method- (JSValue *)globalObject;
Returned content. Because we know that in JavaScript, all global variables and methods are actually a global variable attribute. In the browser, window is used, and what is JavaScriptCore is unknown.
Block can be passed inJSContext
Method,JSValue
NotoBlock
To Block the JavaScript method in Objetive-C. After all, the number and type of Block parameters are fixed. Although the method cannot be extractedJSValue
Provided- (JSValue *)callWithArguments:(NSArray *)arguments;
The method can in turn pass the parameter in to call the method.
1 JSContext *context = [[JSContext alloc] init]; 2 [context evaluateScript:@"function add(a, b) { return a + b; }"]; 3 JSValue *add = context[@"add"]; 4 NSLog(@"Func: %@", add); 5 6 JSValue *sum = [add callWithArguments:@[@(7), @(21)]]; 7 NSLog(@"Sum: %d",[sum toInt32]); 8 //OutPut: 9 // Func: function add(a, b) { return a + b; }10 // Sum: 28
JSValue
Also provides- (JSValue *)invokeMethod:(NSString *)method withArguments:(NSArray *)arguments;
This allows us to directly and simply call methods on objects. If the defined method is a global function, it should beJSContext
OfglobalObject
This method is called on an object. If it is a method on a JavaScript object, the correspondingJSValue
Object call.
Exception HandlingObjective-C exceptions will be caught by Xcode at runtime, whileJSContext
If an exception occurs in the JavaScript executed inJSContext
Captured and stored inexception
Attribute instead of being thrown out. Always checkJSContext
Objectexception
Is it notnil
Obviously it is not suitable. A more reasonable way isJSContext
Object settingsexceptionHandler
Which accepts^(JSContext *context, JSValue *exceptionValue)
Block. The default value isexceptionValue
Assigned to the passedcontext
Ofexception
Attribute:
1 ^(JSContext *context, JSValue *exceptionValue) {2 context.exception = exceptionValue;3 };
We can alsoexceptionHandler
Assign a new Block so that we can immediately know when an exception occurs in JavaScript running:
1 JSContext *context = [[JSContext alloc] init]; 2 context.exceptionHandler = ^(JSContext *con, JSValue *exception) { 3 NSLog(@"%@", exception); 4 con.exception = exception; 5 }; 6 7 [context evaluateScript:@"ider.zheng = 21"]; 8 9 //Output:10 // ReferenceError: Can't find variable: ider
Block usage considerationsFrom the previous examples and introductions, we should have realized the powerful role of Block in JavaScriptCore. It builds more bridges between JavaScript and Objective-C, making intercommunication more convenient. However, it should be noted that the Block is passedJSContext
Object to convert it into a JavaScript method, or assign itexceptionHandler
Attribute,Do not directly use the externally definedJSContext
Object orJSValue
, It should be passed into the Block as a parameter, or throughJSContext
Class Method+ (JSContext *)currentContext;
. Otherwise, the memory cannot be properly released due to loop reference.
For example, the preceding custom exception handling method is assigned to the inputJSContext
Objectcon
Instead of creatingcontext
Objects, although they are actually the same object. This is because the Block will make a strong reference to the Internally used objects created in the external definition, andJSContext
Strong references will also be made to the given blocks, so that a Circular Reference (Circular Reference) will be formed between them so that the memory cannot be normally released.
ForJSValue
It cannot be referenced directly from the external to the Block, because eachJSValue
Both haveJSContext
Reference (@property(readonly, retain) JSContext *context;
),JSContext
Referencing Block also forms a reference loop.