Talk about JavaScriptCore.

Source: Internet
Author: User
Tags instance method

http://www.jianshu.com/p/1328e15416f3/comments/1724404

JavaScript still seems to be the world's most popular language, whether in the Web, server or client has a wide range of applications, many cross-platform scenarios are also implemented using JS, such as the famous Reactjs, Apple introduced the JavaScriptCore library in IOS7, Provide a more simple and convenient way to JS access, iOS7 before the JS operation can only be done through the UIWebView in the
Stringbyevaluatingjavascriptfromstring method, and JavaScriptCore this piece of code open source, can be viewed here, this article briefly introduces JavaScriptCore:

    • Objective-c calling JavaScript
    • JavaScript calls Objective-c
    • Memory management
    • Multithreading

But before that, let's introduce a few basic concepts:

    • Jscontext
      A Jscontext instance represents a JS runtime environment, the JS code needs to be executed within a context, and Jscontext is responsible for managing the life cycle of all objects in the JS virtual machine.
    • Jsvalue
      Represents a JavaScript entity, a jsvalue can represent many JavaScript primitive types such as Boolean, integers, doubles, and even objects and functions. Our operation on JS is through it, and each jsvalue is strongly referencing a context. At the same time, the conversion between OC and JS object is also through it, the corresponding type is converted as follows:

Jsvalue Type Conversions
    • Jsvirtualmachine
      JS code to run the virtual machine, provide javascriptcore to execute the required resources, has its own independent stack and garbage collection mechanism, and through the lock to achieve thread safety, if you need to execute JS code concurrently, you can create different jsvirtualmachine virtual machine objects to achieve;
Objective-c calling JavaScript

OC want to invoke the JS code, first create a Jscontext object instance, and then through the Evaluatescript load JS code into the context object, and then get the JS object, if it is a JS function object, The JS function is called through callwitharguments, and parameters can be passed as an array.

  Test.jsvar appendString =function(name) {Return' String: ' + name; };var arr = [1,2,' Hello World ';TEST.M nsstring *jspath = [[NSBundle Mainbundle] pathforresource:@"Test" oftype:@ "JS"]; NSString *jscontent = [NSString stringwithcontentsoffile:jspath encoding:nsutf8stringencoding Error:nil]; Jscontext *context = [[Jscontext alloc] init]; [Context Evaluatescript:jscontent]; Jsvalue *value = [context[@"appendString"] callwitharguments:@[@"Hello"]; Jsvalue *value1 = context[@"arr"]; NSLog (@"appendstring:%@", [value toString]);  AppendString:string:hello NSLog (@"arr:%@", [value1 ToArray]); //arr: ( //1, //2, //"Hello World" //)            
JavaScript calls Objective-c

JS calls OC There are two ways to implement

    • Blocks Way
      We can use block to expose OC code to Js,javascriptcore will automatically wrap OC block in the JS function, we can directly in JS call the Block function, a bit convenient ~
    JSContext *context = [[JSContext alloc] init];    context[@"sayhi"] = ^(NSString *name) {        NSLog(@"say hi to %@",name);    };    [context evaluateScript:@"sayhi(‘Greg‘)"]; //"say hi to Greg"

Block.png
    • Jsexport protocol
      If you go to the end of the file to see the Jsexport protocol, you will find that this protocol does not actually define anything. JavaScriptCore provides this protocol to the OC Method and attribute to the JS call, wherein the @property will be converted to JS getter and setter method, the instance method will be converted to JS function, and the class method is converted to JS in the global The method of the object.

Jsexport


As an example, our Personprotocol protocol defines the content to be exposed to JS:

Define what needs to be exposed to JS, where we only expose PersonName and Querypersonname interfaces.@protocolPersonprotocol <Jsexport>@property (Nonatomic,CopyNSString *personname;-(NSString *) Querypersonname;@endPerson implements the Personprotocol protocol, and the age and Querypersonage interfaces that they define are not exposed to JS@interfacePerson:NSObject <Personprotocol>@property (Nonatomic,AssignNsinteger age;-(Nsinteger) Querypersonage;@end@implementationPerson@synthesize personname = _personname;-(NSString *) querypersonname{ReturnSelf. PersonName;} -(Nsinteger) querypersonage{ReturnSelf. Age;@endJSContext *context = [[Jscontext alloc] init];Create an object of the person class and assign him to the JS object, *person=[person new];p Erson. PersonName =@ "Greg";p Erson.age = 27;context[@ "person"]= Person //can be called to get Personprotocol exposed content nsstring *personname = [[ Context Evaluatescript:@ "Person.personname"] toString]; //"Greg" nsstring *personname1 = [[Context evaluatescript:< Span class= "hljs-string" >@ "Person.querypersonname ()"] toString]; //"Greg" //js cannot invoke age-related content @ "Person.age"] toInt32]; //0nsinteger age1 = [[Context Evaluatescript:@" person.querypersonage () [] toInt32]; //0              
Memory management

Let's talk about memory management, we know that using arc to manage memory in OC (based on reference counting), but JavaScriptCore is using garbage collection, where all references are strong references, we don't have to worry about their circular references, JS garbage collection can break these strong references, usually we do not need to pay attention to the memory problem when we use the API in JavaScriptCore, because these will be handled automatically, but in some cases we need to pay attention to:

    • Storing JS values in OC objects
      If you store the JS value in the OC object, you need to be careful not to cause circular references, see an example:
//test.jsfunction ClickHandler(button, callback) { this.button = button; this.handler = callback;}//test.m@implement MyButton-(void)setClickHandler:(JSValue*)handler{ _onClickHandler = handler; //导致retain cycle}

The above code can be seen, MyButton onclickhandler strong reference JS handler, and JS button and strong reference MyButton, which will lead to retain cycle of the problem:


Retain cycle

In OC in order to break the circular reference we adopt weak way, but in JavaScriptCore we adopt memory management helper Object Jsmanagedvalue Way, it can help reference technology and garbage collection between the two memory management mechanism to make the correct transfer, So we can use the following methods:

@implement MyButton-(void)setClickHandler:(JSValue*)handler{  _onClickHandler = [JSManagedValue managedValueWithValue:handler];  [_context.virtualMachine addManagedReference:_onClickHandler];}

Jsmanagedvalue itself only weakly reference JS value, need to call Jsvirtualmachine Addmanagedreference:withowner: add it to Jsvirtualmachine, This jsvalue reference will not be released if JavaScript can find the objective-c owner of the Jsvalue.

    • Capture Jscontexts in block
      We know that block will by default strongly reference the object it captures, as shown in the following code, if using the context directly in the block would also cause circular references, which would be preferable to using [Jscontext CurrentContext] to get the current Jscontext:
BadJscontext *context = [[jscontext alloc] init];context[@ "callback"] = ^{jsvalue *object = [JSValue Valuewithnewobjectincontext:context]; return object;}; //goodjscontext *context = [[JSContext Alloc] Init];context[@ "callback"] = ^{jsvalue *object = [jsvalue valuewithnewobjectincontext: [ Span class= "Hljs-type" >jscontext CurrentContext]; return object;};     
Multithreading

The APIs provided in JavaScriptCore are thread-safe, a jsvirtualmachine in a thread, it can contain multiple jscontext, and can be passed to each other, in order to ensure thread safety, these context will run with locks , which can be thought of as serial execution.


The same virtual machine can access each other

If we need to execute the JS code concurrently, we can also specify the virtual machine in which the Jscontext is created, the different virtual machines are in different threads, but if the context does not pass the value directly to each other in different jsvirtualmachine, You need to be aware of the process in use.

JSVirtualMachine *vm1 = [JSVirtualMachine new];JSContext *ctxA1 = [[JSContext alloc] initWithVirtualMachine:vm1];JSContext *ctxA2 = [[JSContext alloc] initWithVirtualMachine:vm1];JSVirtualMachine *vm2 = [JSVirtualMachine new];JSContext *ctxB = [[JSContext alloc] initWithVirtualMachine:vm2];

Different virtual machines can not access references to each other

https://developer.apple.com/videos/play/wwdc2013/615/
https://developer.apple.com/library/prerelease/ios/documentation/Carbon/Reference/WebKit_JavaScriptCore_Ref/



The old boy under the tree (Jane book author)
Original link: http://www.jianshu.com/p/1328e15416f3/comments/1724404
Copyright belongs to the author, please contact the author to obtain authorization, and Mark "book author".

Talk about JavaScriptCore.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.