JavaScript and iOS

We experience many things throughout our daily lives and we tend to label those experiences using very specific terms. A moment was good or bad. A lesson was useful or useless. An emotion was positive or negative. This labelling action makes us feel in control. We process these moments or feelings better this way. But the truth is they only exist.

In our fight to categorise all the things, we forget that no experience is absolute. It does not carry any meaning by itself. We label it.

This fight is also present in the world of software developers. We are constantly pushed to categorise all the technologies and think that only one part of this vast field is “good”. We have surveys that tell us which is the best programming language. We read very popular articles and learn what we should be learning. But all of these things only limit our mind.

No technology, programming language or platform is good or bad. They are tools we built to help us create solutions for people. Some might be more appropriate for some specific cases but that is where this labelling should stop.

A comment from a very similar (and clickbait-y) article to the ones above really stuck with me. The author was saying that they can’t wait until computers can receive natural language instructions and use any available technology (programming, language, framework, platform, etc.) to solve the problem. I loved this comment because it implies that the computer would only judge the usefulness of each piece of technology for the purpose of solving the problem and not have a predefined preference for one.

In the mobile world, there was a very difficult decision to make when designing the most popular platforms today. That decision was about how would developers interact with the platform to build their own apps. Back then there were 2 major options: build the apps using web technologies (HTML5, JavaScript) or use a native technology. For iOS and Android, the decision went towards native development due to the unstable and inflexible nature of the web technologies at that time. Since then we’ve seen newer platforms emerge which support these technologies but have not gained enough popularity.

It wasn’t long before people started labelling things and, due to the huge popularity of iOS and Android, many developers were convinced that native technologies were “better” than web. The most popular arguments against the web technologies were the non-native look and lower performance. Nowadays, these arguments are not so relevant anymore. Performance has increased significantly and not even native apps look native anymore and you can see more and more developers looking into the cross-platform, web-based alternatives.

JavaScriptCore is an iOS framework introduced in version 7 without much popularity. It is a very fast wrapper for WebKit, the JavaScript engine used by Apple in Safari and Google in Chrome. An app can execute JavaScript code using this framework and communicate with that code easily.

The entire JavaScript code in the app must run in a JSContext, and all the values passed to it or returned from it will be wrapped in a JSValue. Because of JavaScript’s dynamic nature, JSValue can be converted in any native type using it’s conversion methods (toBool(), toString()…).

A very simple case where we can use this framework is when we already have a web app that uses some internal JavaScript language that we need to port in a native iOS app. For example, we have a JavaScript function that checks if a person’s CNP (Romanian ID number) is valid or not:

function validCNP( p_cnp ) {  
var i=0 , year=0 , hashResult=0 , cnp=[] , hashTable=[2,7,9,1,4,6,3,5,8,2,7,9];
if( p_cnp.length !== 13 ) { return false; }
for( i=0 ; i<13 ; i++ ) {
cnp[i] = parseInt( p_cnp.charAt(i) , 10 );
if( isNaN( cnp[i] ) ) { return false; }
if( i < 12 ) { hashResult = hashResult + ( cnp[i] * hashTable[i] ); }
}
hashResult = hashResult % 11;
if( hashResult === 10 ) { hashResult = 1; }
year = (cnp[1]*10)+cnp[2];
switch( cnp[0] ) {
case 1 : case 2 : { year += 1900; } break;
case 3 : case 4 : { year += 1800; } break;
case 5 : case 6 : { year += 2000; } break;
case 7 : case 8 : case 9 : { year += 2000; if( year > ( parseInt( new Date().getYear() , 10 ) - 14 ) ) { year -= 100; } } break;
default : { return false; }
}
if( year < 1800 || year > 2099 ) { return false; }
return ( cnp[12] === hashResult );
}

Source: https://github.com/cristian-datu/CNP/blob/master/cnp.js

We could go ahead and rewrite this function in Swift or Objective-C, or we could use this function that is already written for us:

import JavaScriptCore

let context = JSContext()
let script = "function validCNP(p_cnp) {" +
"var i=0, year=0, hashResult=0, cnp=[], hashTable=[2,7,9,1,4,6,3,5,8,2,7,9];" +
"if (p_cnp.length !== 13) { return false; }" +
"for (i=0; i<13; i++) {" +
"cnp[i] = parseInt(p_cnp.charAt(i), 10);" +
"if (isNaN(cnp[i])) { return false; }" +
"if (i<12) {hashResult = hashResult + (cnp[i] * hashTable[i]);}" +
"}" +
"hashResult = hashResult % 11;" +
"year = (cnp[1]*10)+cnp[2];" +
"switch( cnp[0] ) {" +
"case 1 : case 2 : { year += 1900; } break;" +
"case 3 : case 4 : { year += 1800; } break;" +
"case 5 : case 6 : { year += 2000; } break;" +
"case 7 : case 8 : case 9 : { year += 2000; if( year > ( parseInt( new Date().getYear() , 10 ) - 14 ) ) { year -= 100; } } break;" +
"default : { return false; }" +
"}" +
"if( year < 1800 || year > 2099 ) { return false; }" +
"return ( cnp[12] === hashResult );" +
"}"

context.evaluateScript(script)

let validCNP = context.evaluateScript("validCNP('123')")
println(validCNP.toBool()) // false

You can see that we avoided rewriting a pretty complex function which was previously written and tested and which is ready to be used anywhere.

JavaScriptCore’s power lies not only in avoiding repetition but also in communicating with the native platform. JavaScript objects and types can be converted to and from native objects and we can add JavaScript logic basically in any part of our app.

There is also a project which aims to port the Node.Js platform to JavaScriptCore, giving endless possibilities. Another interesting use is embedding a UIWebView inside an app, capturing its JSContext and force it to execute arbitrary code. (Example)

Don’t let labels run your life. Experiment! There is no absolute truth. Truth is a combination of states, perspectives and experiences.

A decision you might see as “good” today, might be the exact opposite after a while. Our mind has an extraordinary ability to analyse the solutions of all the problems we face every day. Don’t stand in its way!


Originally published at appcluj.ro on January 21, 2015.