JavaScriptCore Framework

using javascript in iOS 7
ရေးသားသူ : saturngod

JavaScriptCore framework ဟာ C base API ဖြစ်ပြီး Mac OSX 10.2 မှာ ကတည်းက စပြီးပါတဲ့ framework တစ်ခုပါ။ iOS 7 နဲ့ Mac OS 10.9 မှာ Apple က JavscriptCore ကို native Objective-C API နဲ့ မိတ်ဆက်ခဲ့ပါတယ်။

အရင်တုန်းက Javascript function တွေကို ခေါ်ဖို့အတွက် UIWebView ကနေ တဆင့်

stringByEvaluatingJavaScriptFromString:

နဲ့ ခေါ်ရပါတယ်။ JavaScriptCore framework ဟာ developer တွေကို တွေကို Objective-C ကနေ full javascript runtime access လုပ်ခွင့်ပေးထားပါတယ်။

Javascript ဟာ JSVirtualMachine machine မှာ run ထားပါတယ်။ JSVirtualMachine ဟာ light weight ဖြစ်ပြီးတော့ multithreaded javascript တွေကို အလုပ်လုပ်ပေးနိုင်တယ်။ JSVirtualMachine ထဲမှာ JSContext တွေ ရှိပါတယ်။ JSContexts ဟာ Javascript runtime environment နဲ့ ချိတ်ဆက်ဆောင်ရွက်ပေးပြီးတော့ javascript က global object တွေကို access လုပ်နိုင်တယ်သလို script တွေကိုလည်း execute လုပ်ပေးပါတယ်။

JSContext *context = [[JSContext alloc] initWithVirtualMachine:[[JSVirtualMachine alloc] init]];
context[@"a"] = @5;

အထက်ပါ code မှာ ဆိုရင် javascript က global variable a က နံပတ် ၅ ဖြစ်တယ်လို့ ဆိုထားပါတယ်။ Javascript က variable ကို ပြန်လိုချင်ရင်တော့ JSValue နဲ့ လက်ခံရပါတယ်။

 JSValue *aValue = context[@"a"];
double a = [aValue toDouble];
NSLog(@"%.0f", a);

javascript ကို evaluateScript နဲ့လည်း တိုက်ရိုက် run လို့ရပါတယ်။

[context evaluateScript:@"a = 10"];
JSValue *newAValue = context[@"a"];
NSLog(@"%.0f", [newAValue toDouble]);

Functional Execution

ကျွန်တော်တို့တွေ javascript function ကို objective c မှာလည်း ပြန်ပြီး အသုံးချလို့ရတယ်။

[context evaluateScript:@"var square = function(x) {return x*x;}"];

JSValue *squareFunction = context[@"square"];
NSLog(@"%@", squareFunction);

JSValue *aSquared = [squareFunction callWithArguments:@[context[@"a"]]];
NSLog(@"a^2: %@", aSquared);

JSValue *nineSquared = [squareFunction callWithArguments:@[@9]];
NSLog(@"9^2: %@", nineSquared);

အဲဒီ အခါ အောက်ကလို မျိုး result ရလာပါလိမ့်မယ်။

JSThing[53327:a0b] function (x) {return x*x;}
JSThing[53282:a0b] a^2: 25
JSThing[53282:a0b] 9^2: 81

-callWithArguments method နဲ့ JSValue ကို NSArray နဲ့ argument တွေ ပို့ပေးလို့ရပါတယ်။ အပေါ်က example မှာ argument က ၁ ခုပဲ ဖြစ်တဲ့အတွက် array အခန်းက ၁ ခုပဲ ဖြစ်နေတာပါ။ တကယ်လို့ ၂ ခု သာ ဆိုရင် အခန်း ၂ ခန်းဖြစ်နေပါလိမ့်မယ်။

ဒါ့အပြင် JSContext ဟာ objective-c function ကို parse လုပ်ပေးနိုင်ပါတယ်။

context[@"factorial"] = ^(int x) {
        int factorial = 1;
        for (; x > 1; x--) {
            factorial *= x;
        }
        return factorial;
    };
[context evaluateScript:@"var fiveFactorial = factorial(5);"];
JSValue *fiveFactorial = context[@"fiveFactorial"];
NSLog(@"5! = %@", fiveFactorial);

NSLog က အောက်ကလို ထွက်လာပါမယ်။

JSThing[53327:a0b] 5! = 120

Object Permanence

Objective-C data type ကို jsvalue အနေနဲ့ parse လုပ်တဲ့ အခါ javacsript မှာ အောက်ကလို data type ပြောင်းသွားပါတယ်။

Objective-C Type Javascript Type
nil undefined
NSNull null
NSString string
NSNumber number , boolean
NSDictionary Object object
NSArray Array object
NSDate Date object
NSBlock Function object
id Wrapper object
Class Constructor object

JSExport

ကိုယ်ပိုင် class တစ်ခုကို javascript မှာ parse လုပ်ဖို့ အတွက် JSExport ကို အသုံးပြုရပါတယ်။ အောက်မှာ ဥပမာလေး ကြည့်ပါ။

@protocol ThingJSExports <JSExport>
    @property (nonatomic, copy) NSString *name;
    @end

    @interface Thing : NSObject <ThingJSExports>
    @property (nonatomic, copy) NSString *name;
    @property (nonatomic) NSInteger number;
@end

@implementation Thing
    - (NSString *)description {
        return [NSString stringWithFormat:@"%@: %d", self.name, self.number];
    }
@end

ThingJSExports ဟာ JSExport ကနေ inherits လုပ်ထားပါတယ်။

Thing *thing = [[Thing alloc] init];
thing.name = @"Alfred";
thing.number = 3;
context[@"thing"] = thing;
JSValue *thingValue = context[@"thing"];

Thing object ကို JSContext မှာ ထည့်လိုက်တာ တွေ့ပါလိမ့်မယ်။ JSValue result က ဘာတွေ ထွက်လာမလဲ ဆိုာတကို အောက်ကလို ကြည့်နိုင်ပါတယ်။

NSLog(@"Thing: %@", thing);
NSLog(@"Thing JSValue: %@", thingValue);

Result ဟာ

JSThing[53344:a0b] Thing: Alfred: 3
JSThing[53344:a0b] Thing JSValue: Alfred: 3

ဖြစ်နေတာကို တွေ့ပါလိမ့်မယ်။ Value ပြောင်းပြီး ကြည့်ရအောင်။

thing.name = @"Betty";
thing.number = 8;

NSLog(@"Thing: %@", thing);
NSLog(@"Thing JSValue: %@", thingValue);
JSThing[53344:a0b] Thing: Betty: 8
JSThing[53344:a0b] Thing JSValue: Betty: 8

Javascript ကနေ thing object ကို variable ပြောင်းမယ်ဆိုရင်

 [context evaluateScript:@"thing.name = \"Carlos\"; thing.number = 5"];

NSLog(@"Thing: %@", thing);
NSLog(@"Thing JSValue: %@", thingValue);

NSLog မှာ အောက်ကလို ပေါ်ပါလိမ့်မယ်။

Thing: Carlos: 8
Thing JSValue: Carlos: 8

JavaScripteCore framework ဟာ WebKit ရဲ့ အစိတ်အပိုင်းတစ်ခုဖြစ်ပြီး open-source project ပါ။ သူရဲ့ source code ကို ဒီမှာ ကြည့်နိုင်ပါတယ်။