Cocoa プログラミング

JavaScriptCore

JavaScriptCore では、Objective-C や Swift で記載した独自のクラスも利用できるようになっています。

このクラスの中で JavaScript に固有な undefined の値を扱う方法を調べてみました。

JavaScriptCore で undefined を扱えるメソッドを実装する

JavaScriptCore.framework を使った JavaScript の実行環境では、Objective-C や Swift で記載した独自のクラスも利用できるようになっています。

JSExport プロトコルを継承したプロトコルで定義した機能であれば JavaScript から自由に実行できます。引数や戻り値も、プリミティブ型やNSString などの基本的なオブジェクトの他にも、JSExport に対応したオブジェクトであれば、普段通りの実装で自由にやり取りできるようになっています。

JavaScriptCore でundefined を引数や戻り値に使うには

さて、Objective-C や Swift になくて JavaScript に存在するのがundefined という値です。

要は未定義値 というもので、空を示すnull とも違う、そもそも存在していないものという意味の値になります。


この値を JavaScriptCore で使えるクラスで扱いたい場合には、その値をJSValue 型で扱うようにします。

このJSValue 型というのは、JavaScriptCore 内で扱う JavaScript の変数の型です。 JavaScript の変数では型を気にせず自由に扱えるバリアント型 になっていますが、このJSValue 型が、さまざまな型を一手に引き受けるバリアント型の機能を担っています。 JavaScriptCore のevaluateScript: メソッドを使うと、実行した JavaScript の戻り値がこの型で取得できるので、JavaScriptCore を使い始めてしばらくした人にはきっとお馴染みのオブジェクトでしょう。

このオブジェクトを独自のクラスの引数や戻り値として使うことで、undefined を含むバリアント型の自由な値を、独自のクラスで利用できるようになります。


戻り値でundefined を返すメソッド

たとえば、NSDictionary 型の変数options から、キーを指定して値を取得するメソッドを JavaScript から呼び出せるようにするとします。

このとき変数options に存在するキーが指定された場合はその値を文字列型で返し、指定されたキーが存在しなかった場合は JavaScript 固有のundefined を返すようにしたい場合は、次のようにしてそれを実現できます。

- (JSValue*)getOption:(NSString*)key
{
	if ([options.allKeys containsObject:key])
	{
		return [JSValue valueWithObject:options[key] inContext:[JSContext currentContext]];
	}
	else
	{
		return [JSValue valueWithUndefinedInContext:[JSContext currentContext]];
	}
}

このように、オブジェクトを指定してJSValue を作るときにはvalueWithObject:inContext: メソッドを、undefinedJSValue を作るときにはvalueWithUndefinedInContext: メソッドを使用します。他にもBOOL などのプリミティブ型用のメソッドも用意されています。

これらのメソッドには、その値を使用するJSContext を渡す必要がありますが、現在有効なコンテキストは[JSValue currentContext] で取得できます。

引数でundefined を受け取るメソッド

引数でundefined を受け取りたい場合も同様にJSValue を使用します。

たとえば文字列を受け取りたい引数の型をJSValue にすると、JavaScript から文字列やundefined が渡されたときに、それを一緒くたにして受け取れます。

あとはJSValueisUndefined メソッドを使って引数の値がundefined だったときに特別な処理を実行したり、undefined でなければtoString メソッドを使ってNSString 型の値として取り出したりできます。