2009
12/25

ByteArrayクラスを使って配列やオブジェクトのコピーを生成する

まず、”name”, “birth”, “part”というプロパティを持つオブジェクトを生成し、それぞれのプロパティに値を入れる。

var obj1:Object = new Object();
obj1.name = "John";
obj1.birth = 1940;
obj1.part = "guitar";
trace(obj1.name);	//出力:John

次に、このオブジェクトのコピーを作成し、一部のプロパティを変更するために、以下のスクリプトを実行する。

var obj2:Object = obj1;
obj2.name = "George";
obj2.birth = 1943;
trace(obj1.name, obj2.name);	//出力:George George

すると、コピー先(obj2)だけでなく、コピー元(obj1)のプロパティまでも変更されてしまっている。

これは、obj2 = obj1; としたとき、obj1をコピーしているのではなく、obj1への参照を作成しているにすぎないためである。

・・・というのは実は配列でも同じ事がおこる。で、配列の場合はArray.sliceメソッドを使う事でコピーを作る事ができる(参考:TONPOOBLOG » 配列の(浅い)コピー)んだけど、オブジェクトのコピーを作る時はどうするか?

これまではfor…inを使ってプロパティをコピーしていました。

var obj2:Object = new Object();
for (var name:String in obj1) {
	obj2[name] = obj1[name];
}
obj2.name = "George";
obj2.birth = 1943;
trace(obj1.name, obj2.name);	//出力:John George

ところが、flash-jpの以下のスレッドでByteArrayクラスというのがあることを発見。

FLASH-JP.COM – フォーラム Re: SharedObjectで任意のデータを保存したい

早速ヘルプを参照。

ByteArray – ActionScript 3.0 コンポーネントリファレンスガイド

よくわからないけど、こういうことかな?

//ByteArrayインスタンスを生成
var myByteArray:ByteArray = new ByteArray();
//コピー元ObjectのバイナリデータをByteArrayインスタンスに書き込み
myByteArray.writeObject(obj1);
//ByteArrayインスタンスのデータをコピー先Objectに読み込み
var obj2:Object = myByteArray.readObject();

と思ったら、以下のエラーが。

Error: Error #2030: ファイルの終端 (EOF) が検出されました。
at flash.utils::ByteArray/readObject()
at Sample()

どうやら、先のflash-jpのnekoyukiさんの投稿にもあったように、一度ByteArray.compressByteArray.uncompressしないとダメなようですね。

わざわざ圧縮→解凍などという手間をかけずとも、ByteArray.positionプロパティの値を0にし、ByteArrayのファイルポインタの位置を先頭に戻すことで対応できました!(flash-jpのスレッドでの野中先生のレスから判明しました。野中先生ありがとうございます!)

//ByteArrayインスタンスを生成
var myByteArray:ByteArray = new ByteArray();
//コピー元ObjectのバイナリデータをByteArrayインスタンスに書き込み
myByteArray.writeObject(obj1);
//ByteArrayのファイルポインタの位置を先頭に移す
myByteArray.position = 0;
//ByteArrayインスタンスのデータをコピー先Objectに読み込み
var obj2:Object = myByteArray.readObject();

trace(obj2.name, obj2.birth, obj2.part);	//出力:John 1940 guitar

となると、同じくflash-jpのnekoyukiさんの書いたように、メソッドにしてしまったほうが楽そうです。配列のコピーにも使えますしね。ということでできあがったサンプル用のドキュメントクラス(Sample.as)は以下の通り。

package  {
	import flash.display.MovieClip;
	import flash.utils.ByteArray;

	public class Sample extends MovieClip{

		public function Sample() {
			var obj1:Object = new Object();
			obj1.name = "John";
			obj1.birth = 1940;
			obj1.part = "guitar";

			var obj2:Object = byteCopy(obj1);
			obj2.name = "George";
			obj2.birth = 1942;
			trace(obj1.name, obj2.name);	//出力:John George

			var array1:Array = ["John", "Paul", "George", "Ringo"];
			var array2:Array = byteCopy(array1);
			array2[3] = "Stuart";
			trace(array1);	//出力:John,Paul,George,Ringo
			trace(array2);	//出力:John,Paul,George,Stuart
		}

		//バイナリデータのコピーメソッド
		public function byteCopy(objFrom:*):*{
			//ByteArrayインスタンスを生成
			var myByteArray:ByteArray = new ByteArray();
			//コピー元ObjectのバイナリデータをByteArrayインスタンスに書き込み
			myByteArray.writeObject(objFrom);
			//ByteArrayのファイルポインタの位置を先頭に移す
			myByteArray.position = 0;
			//ByteArrayインスタンスのデータを返す
			return myByteArray.readObject();
		}
	}
}
Filed under: actionscript3Comments (0)— tonpoo @ 12:57 PM

コメントはまだありません »

コメントはまだありません。

この投稿へのコメントの RSS フィード。 TrackBack URL

コメントする