Мы сталкиваемся со многими вещами в течение нашей повседневной жизни, и мы склонны обозначать этот опыт, используя очень конкретные термины. Момент был хорошим или плохим. Урок был полезным или бесполезным. Эмоция была положительной или отрицательной. Это действие по навешиванию ярлыков заставляет нас чувствовать себя под контролем. Так мы лучше обрабатываем эти моменты или чувства. Но правда в том, что они только существуют.

В нашей борьбе за классификацию всех вещей мы забываем, что ни один опыт не является абсолютным. Само по себе оно не несет никакого смысла. Мы помечаем его.

Эта борьба также присутствует в мире разработчиков программного обеспечения. Нас постоянно подталкивают классифицировать все технологии и думать, что только одна часть этого обширного поля является хорошей. У нас есть опросы, которые говорят нам, какой лучший язык программирования. Мы читаем очень популярные статьи и изучаем то, что должны изучать. Но все эти вещи только ограничивают наш разум.

Ни одна технология, язык программирования или платформа не являются хорошими или плохими. Это инструменты, которые мы создали, чтобы помочь нам создавать решения для людей. Некоторые из них могут быть более подходящими для некоторых конкретных случаев, но на этом следует остановиться.

Комментарий из очень похожей (и кликбейтной) статьи на те, что выше, действительно зацепил меня. Автор говорил, что они не могут ждать, пока компьютеры смогут получать инструкции на естественном языке и использовать любую доступную технологию (программирование, язык, фреймворк, платформу и т. д.) для решения проблемы. Мне понравился этот комментарий, потому что он подразумевает, что компьютер будет судить о полезности каждой технологии только для решения проблемы, а не отдавать предпочтение какой-то одной из них заранее.

В мобильном мире было очень трудно принять решение при разработке самых популярных сегодня платформ. Это решение касалось того, как разработчики будут взаимодействовать с платформой для создания собственных приложений. Тогда было 2 основных варианта: создавать приложения с использованием веб-технологий (HTML5, JavaScript) или использовать нативную технологию. Для iOS и Android решение было принято в пользу нативной разработки из-за нестабильности и негибкости веб-технологий того времени. С тех пор мы наблюдаем появление новых платформ, поддерживающих эти технологии, но не получивших достаточной популярности.

Это было незадолго до того, как люди начали маркировать вещи, и из-за огромной популярности iOS и Android многие разработчики были убеждены, что нативные технологии «лучше», чем веб. Самыми популярными аргументами против веб-технологий были ненативный вид и более низкая производительность. Сейчас эти аргументы уже не так актуальны. Производительность значительно возросла, и даже нативные приложения больше не выглядят нативными, и вы можете видеть, как все больше и больше разработчиков изучают кроссплатформенные веб-альтернативы.

JavaScriptCore — это фреймворк для iOS, представленный в седьмой версии и не очень популярный. Это очень быстрая оболочка для WebKit, движка JavaScript, используемого Apple в Safari и Google в Chrome. Приложение может выполнять код JavaScript с помощью этой платформы и легко взаимодействовать с этим кодом.

Весь код JavaScript в приложении должен выполняться в JSContext, и все значения, переданные ему или возвращенные из него, будут заключены в JSValue. Из-за динамической природы JavaScript JSValue может быть преобразован в любой нативный тип с помощью его методов преобразования (toBool(), toString()…).

Очень простой случай, когда мы можем использовать эту структуру, — это когда у нас уже есть веб-приложение, использующее некоторый внутренний язык JavaScript, который нам нужно перенести в родное приложение для iOS. Например, у нас есть функция JavaScript, которая проверяет, действителен ли CNP (румынский идентификационный номер) человека:

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 );
}

Источник: https://github.com/cristian-datu/CNP/blob/master/cnp.js

Мы могли бы пойти дальше и переписать эту функцию на Swift или Objective-C, или мы могли бы использовать эту функцию, которая уже написана для нас:

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

Как видите, мы избежали переписывания довольно сложной функции, которая уже была написана и протестирована ранее и готова к использованию где угодно.

Сила JavaScriptCore заключается не только в том, чтобы избегать повторений, но и в общении с нативной платформой. Объекты и типы JavaScript можно преобразовывать в нативные объекты и из них, и мы можем добавлять логику JavaScript практически в любую часть нашего приложения.

Существует также проект, целью которого является перенос платформы Node.Js на JavaScriptCore, дающий бесконечные возможности. Еще одно интересное использование — встраивание UIWebView в приложение, захват его JContext и принудительное выполнение произвольного кода. ("Пример")

Не позволяйте ярлыкам управлять вашей жизнью. Эксперимент! Абсолютной истины не бывает. Истина – это сочетание состояний, перспектив и переживаний.

Решение, которое сегодня кажется вам «хорошим», через некоторое время может оказаться совершенно противоположным. Наш разум обладает необычайной способностью анализировать решения всех проблем, с которыми мы сталкиваемся каждый день. Не стой у него на пути!

Первоначально опубликовано на appcluj.ro 21 января 2015 г.