Pull to refresh

Копирование объектов с помощью ByteArray

Reading time 4 min
Views 4.9K
Original author: ByteArray.org

Копирование простых объектов


Чаще всего ByteArray используют для копирования объектов. AMF сериализатор и десериализатор (не люблю эти слова, но не нашёл подходящего перевода) доступен через ByteArray API. Для дублирования объектов с помощью ByteArray мы будем использовать методы writeObject и readObject:

// Создаём пустой ByteArray
var stream:ByteArray = new ByteArray();
// Создаём объект
var parameters:Object = { age : 25, name : "Bob" };
// «Переводим» объект в формат AMF и сохраняем его в ByteArray
stream.writeObject( parameters );
// Сбрасываем позицию
stream.position = 0;
// Считываем объект
var objectCopy:Object = stream.readObject();


На основе этого кода можно создать функцию, которую мы сможем использовать для копирования объектов:

function copyObject(objectToCopy:*):*
{
  var stream:ByteArray = new ByteArray();
  stream.writeObject( objectToCopy );
  stream.position = 0;
  
  return stream.readObject();
}


Чтобы удостовериться, что мы действительно создали отдельную копию объекта, мы можем модифицировать свойства исходного объекта:

// Создаём объект
var parameters:Object = { age : 25, name : "Bob" };
var parametersCopy:Object = copyObject ( parameters );
parameters.nom = "Stevie";
/* outputs :
name : Bob
age : 25
*/
for ( var p:String in parametersCopy )
{
	trace( p, " : ", parametersCopy[p] );
}

function copyObject ( objectToCopy:* ):*
{
	var stream:ByteArray = new ByteArray();
	stream.writeObject( objectToCopy );
	stream.position = 0;
	return stream.readObject();
}


Чуть ниже мы узнаем, как можно сохранять и восстанавливать более сложные типы данных, с помощью ByteArray.

Копирование пользовательских классов


Код, описанный ранее, не будет работать для пользовательских классов, которые вы можете использовать в вашем приложении. Разберём очень простой пример, скажем, вам нужно использовать объекты класса User:

package
{
	public class User
	{
		private var _firstName:String;
		private var _lastName:String;
		
		public function set firstName (firstName:String):void
		{
			_firstName = firstName;
		}
		
		public function set lastName (lastName:String):void
		{
			_lastName = lastName;
		}
		
		public function get firstName ():String
		{
			return _firstName;
		}
		
		public function get lastName ():String
		{
			return _lastName;
		}
	}
}


Вам может понадобиться сохранить объект класса User на сервере в виде бинарных данных или локально в SharedObject. Если вы попробуете сохранить объект класса User в ByteArray и извлечь его, то при чтении, Flash Player будет проверять, был ли зарегистрирован тип User ранее, если нет, то этот объект будет «разбираться» как обычный объект:

// Создаём экземпляр класса User
var myUser:User = new User ();

// Устанавливаем свойства
myUser.firstName = "Stevie";
myUser.lastName = "Wonder";

// outputs :[object User]
trace ( myUser );

// Создаём ByteArray для сохранения экземпляра
var bytes:ByteArray = new ByteArray();

// Сохраняем экземпляр
bytes.writeObject ( myUser );

// Сбрасываем позицию
bytes.position = 0;

// outputs : false
trace ( bytes.readObject() is User );


Чтобы зарегистрировать тип User в Flash Player можно использовать метод registerClassAlias. После этого объекты класса User можно будет «разбирать» с помощью ByteArray.

// Создаём экземпляр класса User
var myUser:User = new User ();

// Устанавливаем свойства
myUser.firstName = "Stevie";
myUser.lastName = "Wonder";

// outputs :[object User]
trace ( myUser );

// Регистрируем тип User для «разбора»
registerClassAlias ( "userTypeAlias", User );

// Создаём ByteArray для сохранения экземпляра
var bytes:ByteArray = new ByteArray();

// Сохраняем экземпляр
bytes.writeObject ( myUser );

// Сбрасываем позицию
bytes.position = 0;

// При «разборе» сохраненённого объекта, автоматически будет использоваться нужный тип
var storedUser:User = bytes.readObject() as User;

// outputs : true
trace ( storedUser is User );

// outputs : Stevie Wonder
trace ( storedUser.firstName, storedUser.lastName );


Используя эту технику мы можем сохранять и восстанавливать экземпляры любых пользовательских классов. Как вы можете увидеть, сейчас мы работаем с копией объекта пользовательского класса:


storedUser.firstName = "Bobby";
storedUser.lastName = "Womack";

// outputs : Stevie Wonder
trace ( myUser.firstName, myUser.lastName );

// outputs : Bobby Womack
trace ( storedUser.firstName, storedUser.lastName );


Нужно помнить, что некоторые нативные типы данных не могут быть сериализованы/десериализованы с помощью AMF. Это относится к таким визуальным объектам, например DisplayObject. Например, если вы попробуете «разобрать» экземпляр MovieClip (если бы это можно было сделать, то это было бы очень круто =), то у вас ничего не получится:


// Создаём ByteArray
var bytes:ByteArray = new ByteArray();

// Пытаемся сохранить объетк DisplayObject
bytes.writeObject ( new MovieClip() );

// Сбрасываем позицию
bytes.position = 0;

// outputs : undefined
trace ( bytes.readObject() );


Поддержка визуальных объектов в AMF3 была бы очень полезным дополнением для списка поддерживаемых в AMF типов.

От переводчика


Мне нравится «упаковывать» все часто используемые функции в отдельные классы со статическими функциями и данный случай с копированием объектов не стал исключением =) Для этого я создал небольшой класс и попытался сохранить описанным способом некоторый свой класс, в ходе небольшого эксперимента я наткнулся на небольшой нюанс, который не описан в исходной статье: если конструктор классов нужного вам типа требует передачи обязательных параметров, то при «восстановлении» объекта возникнет ошибка, связанная с тем, что в конструктор не были переданы нужные данные. Благо, данная проблема не возникает, если конструктор требует передачи параметров, но они не являются обязательными.

Кстати, у себя в примере, я попробовал скопировать Array и Vector., и у меня всё это получилось). Необходимость сохранения/чтения данных в SharedObject у меня возникает довольно часто, поэтому, думаю, что данный способ разбора и копирования сложных классов будет мне очень и очень полезен.

Исходник примера
Tags:
Hubs:
+24
Comments 10
Comments Comments 10

Articles