Object interaction and management tutorial of JavaScriptCore framework in iOS7

Source: Internet
Author: User

In the previous article, the basic usage of the JavaScriptCore framework added in iOS7 is simple, convenient, and efficient. However, it is only applicable to basic types such as numeric, Boolean, string, and array. This article will expand to a more complex type and introduce how the powerful framework allows direct intercommunication between Objective-C objects and JavaScript objects.

For convenience, the following JSContext object will be added to all the following code:logMethod andeventHandler

JSContext * context = [[JSContext alloc] init];
Context. exceptionHandler = ^ (JSContext * con, JSValue * exception ){
NSLog (@ "% @", exception );
Con. exception = exception;
};


Context [@ "log"] = ^ (){
NSArray * args = [JSContext currentArguments];
For (id obj in args ){
NSLog (@ "% @", obj );
}
};

Key-Value Pair Programming-Dictionary

JSContext does not allow direct conversion of Objective-C and JavaScript objects. After all, the object-oriented design of the two is different: the former is based onclassThe latter is based onprototype. However, all objects can be considered as a set of key-value pairs, so objects in JavaScript can be returned to Objective-CNSDictionaryType.

JSValue * obj = [context evaluateScript: @ "var jsObj = {number: 7, name: 'ider '}; jsObj"];
NSLog (@ "% @, % @", obj [@ "name"], obj [@ 'number']);
NSDictionary * dic = [obj toDictionary];
NSLog (@ "% @, % @", dic [@ "name"], dic [@ 'number']);
// Output:
// Ider, 7
// Ider, 7
Similarly, NSDicionary and NSMutableDictionary can be directly called as objects after being passed into JSContext:


NSDictionary * dic ={ "name": @ "Ider", @ "#": @ (21 )};
Context [@ "dic"] = dic;
[Context evaluateScript: @ "log (dic. name, dic ['#'])"];
// Output:
// Ider
// 21


Language shuttle-JSExport Protocol

JavaScript can be detached fromprototypeThe inheritance fully uses JSON to define the object, but the Objective-C programming cannot be separated from the class or inherit the write code. Therefore, JavaScriptCore providesJSExportAs an intercommunication protocol between two languages.JSExportNo method is specified (@optional), But all of them inherit the Protocol (@protocol(Note that not the methods defined in the Objective-C Class (@ interface) can beJSContext. The language is a bit difficult to express. It is clearer to use examples.

@ Protocol PersonProtocol


@ Property (nonatomic, retain) NSDictionary * urls;
-(NSString *) fullName;


@ End


@ Interface Person: NSObject


@ Property (nonatomic, copy) NSString * firstName;
@ Property (nonatomic, copy) NSString * lastName;


@ End;


@ Implementation Person


@ Synthesize firstName, lastName, urls;


-(NSString *) fullName {
Return [NSString stringWithFormat: @ "% @", self. firstName, self. lastName];
}


@ End

In the above Code,PersonProtocolAnd let it inherit the mysteriousJSExportProtocol, as defined in the new protocolurlsAttributes andfullNameMethod. And then definesPersonClass, in addition to making it implementPersonProtocolThe firstName and lastName attributes are also defined. The fullName method returns the combination of the two names.

CreatePersonObject, and thenJSContextAnd try to use JavaScript to access and modify the object.

// Initialize target person
Person * person = [[Person alloc] init];
Context [@ "p"] = person;
Person. firstName = @ "Idera ";
Person. lastName = @ "Zheng ";
Person. urls @ = @ {"site": @ "http://www.iderzheng.com "};

// OK to get FullName
[EvaluateScript context: @ "log (p. fullName ();"];
// Can not access firstname
[EvaluateScript context: @ "log (p. firstName)"];
// OK to access object as dictionary
[EvaluateScript context: @ "log ('site: 'P. urls. site, 'blog: 'P. urls. blog)"];
// OK to change urls property
[EvaluateScript context: @ "= {p. urls blog: 'http://blog.iderzheng.com '}"];
[EvaluateScript context: @ "log ('------- after change urls')"];
[EvaluateScript context: @ "log ('site: 'P. urls. site, 'blog: 'P. urls. blog)"];

// Affect on Objective-C side as well
NSLog (@ "% @", person. urls );

// Output:
// IDER Zheng
// Undefined
// Undefined
// Site:
// Http: // www.iderzheng.com
// Blog:
// Undefined
// ------- AFTER CHANGE URLS
// Site:
// Undefined
// Blog:
// Http: // blog.iderzheng.com
//{
// Blog = "http://blog.iderzheng.com ";
//}

The output results show thatfirstNameAndlastNameThe result isundefinedBecause they do not haveJSExport. But this does not affectfullName()To obtain the values of the two attributes. As mentioned earlierNSDictionaryTypeurls, You canJSContextIs used as an object, and can also be correctlyurlsAssign a new value and reflect it to the actual Objective-CPersonObject.

JSExportNot only can the property be correctly reflected in JavaScript, but the property features are also guaranteed to be correct. For example, an attribute is declaredreadonlyIn JavaScript, only the attribute value can be read, and new values cannot be assigned.

For multi-parameter methods, JavaScriptCore converts each part of the Objective-C method into uppercase letters and removes the colon. For example, the method in the following protocol is called in JavaScript:doFooWithBar(foo, bar);

@ Protocol MultiArgs
-(Void) doFoo :( id) foo withBar :( id) bar;
@ End

If you want a method to have a short name in JavaScript, you need to use the macro provided in JSExport. h:JSExportAs(PropertyName, Selector).

@ Protocol LongArgs

JSExportAs (testArgumentTypes,
-(NSString *) testArgumentTypesWithInt :( int) I double :( double) d
Boolean :( BOOL) B string :( NSString *) s number :( NSNumber *) n
Array :( NSArray *) a dictionary :( NSDictionary *) o
);

@ End

For example, in the protocol defined above, you only need to usetestArgumentTypes(i, d, b, s, n, a, dic);.

Although the JavaScriptCore framework does not yet have an official programming guide, the description of the mysterious protocol in the JSExport. h file is more detailed, one of which is described as follows:

By default no methods or properties of the Objective-C class will be exposed to JavaScript, however methods and properties may explicitly be exported. for each protocol that a class conforms to, if the protocol inparameters ates the protocol JSExport, then the protocol will be interpreted as a list of methods and properties to be exported to JavaScript.

Here, the word "ineffecate" is worth further consideration. After verification, it can only be inherited directly.JSExportCustom protocol (@protocol)JSContext. That is to say, if other protocols inheritPersonProtocolThe defined methods are not introducedJSContext. The source code shows that the JavaScriptCore framework usesclass_copyProtocolListMethod to find the Protocol that the class complies with, and then passprotocol_copyProtocolListCheck whether it complies with the JSExport protocol to reflect the method to JavaScript.

For the defined class extension protocol-class_addProtocol

For the custom Objective-C class, you can use the previous method to customize the inheritance.JSExportTo achieve interaction with JavaScript. None of the defined system classes or library classes introduced from the outside will pre-define the Protocol to provide interaction with JavaScript. Fortunately, Objective-C can modify the class nature at runtime.

For example, in the following exampleUITextFieldAdded the Protocol so that it can be directly accessed in JavaScripttextAttribute. This interface is as follows:

@ Protocol JSUITextFieldExport

@ Property (nonatomic, copy) NSString * text;

@ End

Thenclass_addProtocolAdd the Protocol to it:

-(Void) viewDidLoad {
[Super viewDidLoad];

TextField. text = @ "7 ";
Class_addProtocol ([UITextField class], @ protocol (JSUITextFieldExport ));
}

ForUIButtonAdd the following event as long astextFieldInputJSContextAnd then read itstextValue, which is re-assigned after auto-increment 1:

-(IBAction) pressed :( id) sender {
JSContext * context = [[JSContext alloc] init];

Context [@ "textField"] = textField;

NSString * script = @ "var num = parseInt (textField. text, 10 );"
"++ Num ;"
"TextField. text = num ;";
[Context evaluateScript: script];
}

When you click UIButton, you will seeUITextFieldThe valueJSExportProtocols allow them to communicate with each other directly in Objective-C and JavaScript.


Garbage Collection

Although Objetive-C and JavaScript are both object-oriented languages, they allow programmers to concentrate on business logic without worrying about memory reclaim. However, the memory review mechanism is different between the two. Objective-C is based on Reference count, and the Xcode compiler then supports Automatic Reference count (ARC, Automatic Reference Counting ); javaScript uses the Garbage Collection mechanism (GC and Garbage Collection) as Java/C # does ). Conflicts may occur when two different memory recovery mechanisms are used in the same program.

For example, create a temporary Objective-C object in a method and add itJSContextUsed in JavaScript variables. Because the variables in JavaScript are referenced, they will not be released for recycling. However, objects in Objective-C may change the reference count to 0 after the method call ends, and the memory will be recycled, therefore, the JavaScript layer may also cause incorrect access.

Similarly, if you useJSContextCreates an object or array and returnsJSValueTo Objective-C, even ifJSValueVariableretainBut the memory may be released because the variables in JavaScript are not referenced.JSValueIt's useless.

How to handle the object memory in the two memory recovery mechanisms becomes a problem. JavaScriptCore providesJSManagedValueType helps developers better manage object memory.

@ Interface JSManagedValue: NSObject

// Convenience method for creating JSManagedValues from JSValues.
+ (JSManagedValue *) managedValueWithValue :( JSValue *) value;

// Create a JSManagedValue.
-(Id) initWithValue :( JSValue *) value;

// Get the JSValue to which this JSManagedValue refers. If the JavaScript value has been collected,
// This method returns nil.
-(JSValue *) value;

@ End

As mentioned in introduction to iOS7 new JavaScriptCore frameworkJSVirtualMachineProvides resources for the execution of the entire JavaScriptCore.JSValueConvertJSManagedValueYou can addJSVirtualMachineSo that objects can be correctly accessed on both the Objective-C and JavaScript sides during the runtime without causing unnecessary trouble.

@ Interface JSVirtualMachine: NSObject

// Create a new JSVirtualMachine.
-(Id) init;

// AddManagedReference: withOwner and removeManagedReference: withOwner allow
// Clients of JSVirtualMachine to make the JavaScript runtime aware
// Arbitrary external Objective-C object graphs. The runtime can then use
// This information to retain any JavaScript values that are referenced
// From somewhere in said object graph.
//
// For correct behavior clients must make their external object graphs
// Reachable from within the JavaScript runtime. If an Objective-C object is
// Reachable from within the JavaScript runtime, all managed references
// Transitively reachable from it as recorded
// AddManagedReference: withOwner: will be scanned by the garbage collector.
//
-(Void) addManagedReference :( id) object withOwner :( id) owner;
-(Void) removeManagedReference :( id) object withOwner :( id) owner;

@ End

Learn more-Source Code

I have already introduced the introduction of JavaScriptCore in iOS7, which is actually an open-source framework, you can also easily add source code for compilation and use.

Read the source code to learn more about how JavaScriptCore is implemented. You can also pay attention to more details during development to avoid errors. If you want to read the source code of the framework, you can click here (source code 1, source code 2, source code 3 ).

The code and examples in this article are relatively simple. If you want to learn more about the use of JavaScriptCore, here are detailed test cases to provide some clues. However, not all test cases will pass in iOS7. This is probably because the JavaScriptCore used in the test case is implemented for chromium, and iOS7 is webkit.

References:
  1. Steamclock Software-Apple's new Objective-C to Javascript Bridge
  2. JavaScriptCore and iOS 7? Big Nerd Ranch BlogBig Nerd Ranch Blog
  3. IOS 7 Development ~ JavaScriptCore (2)-AFU's column-blog channel-CSDN. NET
  4. API in trunk/Source/JavaScriptCore-WebKit
  5. Objective-C Runtime Reference
  6. Automatic Reference Counting vs. Garbage Collection-The oxygen gene Language Wiki

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.