JavaScriptCore Framework — JSExport and Memory Management
JavaScript can define objects entirely with JSON without any prototype-based inheritance, but Objective-C code can't exist without classes and inheritance. That's why JavaScriptCore provides as an interoperability protocol between the two languages. itself defines no methods — not even optional ones () — but any methods defined in protocols that inherit from (note: protocols, not Objective-C classes ) will be accessible within a . In the code above, a is defined that inherits from the mysterious protocol, declaring a property and a method. A class is then defined; in addition to conforming to , it also defines and properties. The method returns the combination of both name parts. Now let's create a object, pass it into a , and try to access and modify it from JavaScript. The output clearly shows that accessing and returns , because they have no linkage to JavaScript. This does not, however, affect getting the correct combined value from . As mentioned earlier, the -typed property can be used as an object in the , and assigning a new value to it is reflected correctly on the Objective-C object. not only exposes properties to JavaScript correctly, but also ensures their attributes are respected — for example, if a property is declared in the protocol, it can only be read in JavaScript and cannot be assigned a new value. For multi-parameter methods, JavaScriptCore merges the different parts of an Objective-C method name, capitalizing the letter after each colon and removing the colons. For example, the method in the protocol below would be called in JavaScript as : If you want a method to have a shorter name in JavaScript, use the macro provided in : . For example, the method defined in the protocol above can be called in JavaScript simply as . Although there is no official programming guide for the JavaScriptCore framework, the description of the protocol in is fairly detailed. One part states: 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 incorporates the protocol JSExport, then the protocol will be interpreted as a list of methods and properties to be exported to JavaScript. The word **** is worth noting here. Testing confirms that only custom protocols () that directly inherit from are accessible in a . In other words, if another protocol inherits from , methods defined in that second protocol will not be exposed to the . From the source code, you can see that the JavaScriptCore framework uses to find the protocols a class conforms to, then for each protocol uses to check if it directly conforms to , and only then exposes those methods to JavaScript. Extending Protocols for Defined Classes — For custom Objective-C classes, you can use the approach above — defining a protocol that inherits from — to enable interoperability with JavaScript. For system classes or third-party library classes that are already defined, they won't pre-define any such protocol. Fortunately, Objective-C allows modifying class characteristics at runtime. The example below adds a protocol to so that its property can be accessed directly from JavaScript: Then use the runtime's to add this protocol: Add the following event to a . The method passes the into a , reads its value, increments it by 1, and assigns the new value back: Result: When you tap the , you can see the value incrementing continuously, demonstrating that for already-defined classes, you can also add the magical protocol at runtime to enable seamless interoperability between Objective-C and JavaScript. Different Memory Management Models — Reference Counting vs. Garbage Collection Although both Objective-C and JavaScript are object-oriented languages that let programmers focus on business logic without worrying about memory reclamation, their memory management mechanisms are entirely different. Objective-C uses reference counting, with Xcode's compiler adding support for Automatic Reference Counting (ARC); JavaScript, like Java or C#, uses Garbage Collection (GC)). When two different memory management schemes are used within the same program, conflicts can arise. For example, suppose you create a temporary Objective-C object inside a method and add it to a for use in a JavaScript variable. Because the JavaScript variable holds a reference, the JavaScript side won't release the object, but on the Objective-C side the object's reference count may drop to zero after the method returns, freeing its memory and causing errors on the JavaScript side. Similarly, if you use a to create an object or array and return a to Objective-C — even if you the variable — the JavaScript side may release it due to no remaining references, rendering the corresponding useless. Managing object memory correctly between two different memory management systems is a real challenge. JavaScriptCore provides the type to help developers better manage object memory. Since provides resources for the entire JavaScriptCore execution, once you convert a to a , you can add it to the . This ensures that both the Objective-C and JavaScript sides can correctly access the object during its lifetime, without any unnecessary issues. Code: All code from this post can be found on my GitHub . References: Object Interaction and Management in iOS 7's JavaScriptCore Framework wiki-JavaScriptCore