sfxworks
sfxworks

Reputation: 1091

How do I serialize Vector.<Customobject>?

http://jacksondunstan.com/articles/1642 I followed this to the T, yet I'm running into issues. I'm trying to save a bunch of icons. They have a custom class "Iconn" and are stored in a Vector.<Iconn> for future use. Once the user adds a new icon, I open up a filestream and use it to write the entire vector.

        public function addShortcut(f:File):void
    {
        //Display on side
        icons.reverse(); //Add to the front so it displays on the top.
        icons.push(new Iconn(f)); //Use 16x16 bitmap

        addChild(icons[icons.length - 1]);
        icons.reverse();

        //Save object
        fs = new FileStream();
        fs.open(shortcuts, FileMode.WRITE);
        fs.writeObject(icons);
        fs.close();

        reorder(); //Reorganizes the icons on the screen.
    }

This works all and well with no errors, but when I try to re-launch the application with some icons saved, the vector doesn't even exist.

    icons = new Vector.<Iconn>();
    if (shortcuts.exists)
    {
        trace("Shortcuts exist..adding");
        fs = new FileStream();
        fs.open(shortcuts, FileMode.READ);
        icons = fs.readObject() as Vector.<Iconn>;
        fs.close();
        trace("icons = " + icons); //TypeError: Error #1009: Cannot access a property or method of a null object reference.
        trace("icons length  = " + icons.length); //TypeError: Error #1009: Cannot access a property or method of a null object reference.
    }

I tried adding registerClassAlias("Vector.<Iconn>", Vector.<Iconn>);, but then I get a compiler error 1067: Implicit coercion of a value of type __AS3__.vec:Vector.<Iconn> to an unrelated type Class.

Edit: Here is my Iconn class http://pastebin.com/5TujzpvR

Upvotes: 0

Views: 203

Answers (1)

BadFeelingAboutThis
BadFeelingAboutThis

Reputation: 14406

There's a few reasons this isn't working.

  1. When objects are unserialized, you cannot pass parameters to their constructors. This means that you either need to take out all constructor arguments of ALL classes nested inside your object, or make them all optional by giving them default values.

  2. You have to register every single non-primitive class you use in the object being serialized (including the object's class itself). This includes nested classes. In your case, this includes at least:

    flash.display.Bitmap;
    flash.display.Sprite;
    flash.events.MouseEvent;
    flash.filesystem.File;
    fl.transitions.Tween;
    fl.transitions.easing.Strong;
    

    Plus anything referenced inside of those classes.

  3. Serializing display objects just doesn't work* (it is technically possible with a custom class that implements IExternalizable, but it's quite involved). If you want an example, there is one here.


The best way to serialize display objects, is to create a very very basic class that contains the bare minimum data needed to reconstruct your display object.

In your case, it looks like all you really need is bitmap data. So you could make a simple class like the following:

package 
{
    import flash.geom.Rectangle;
    import flash.utils.ByteArray;

    public class SaveData 
    {
        public var imgBytes:ByteArray;
        public var bounds:Rectangle;
        public var transparent:Boolean;
    }
}

All it stores is the raw bitmap data (a byte array of pixel values), and bounds of the bitmap.

First, you need to register all the classes used. That would look like this:

        //you need to register your class that you're using writeObject on
        registerClassAlias("SaveData", SaveData); 

        //you also need to register the two classes that are referenced in your SaveData class
        registerClassAlias("flash.utils.ByteArray", ByteArray);
        registerClassAlias("flash.geom.Rectangle", Rectangle);

        //you ALSO need to register Point since it's referenced inside the Rectangle class
        registerClassAlias("flash.geom.Point", Point);

Now, to save it, do mostly what you're already doing:

//create a vector to store your list of items to save
var saveArray:Vector.<SaveData> = new Vector.<SaveData>();

//loop through all your icons and do the following in the loop (where bitmap is the icon's bitmap):

var saveData:SaveData = new SaveData();
saveData.bounds = bitmap.getBounds(bitmap);
saveData.imgBytes = bitmap.bitmapData.getPixels(saveData.bounds);
saveData.transparent = bitmap.bitmapData.transparent;
saveArray.push(saveData);

//write the Vector to the file
fs = new FileStream();
fs.open(shortcuts, FileMode.WRITE);
fs.writeObject(saveArray);
fs.close();

Now, when you're ready to load it all back in:

fs = new FileStream();
fs.open(shortcuts, FileMode.READ);
var saveArray:Vector.<SaveData> = fs.readObject() as Vector.<SaveArray>;
fs.close();

//now loop through your array and re-create all your icons.

for(var i:int=0;i<saveArray.length;i++){
    var bmd:BitmapData = new BitmapData(saveArray[i].bounds.width, saveArray[i].bounds.height, saveArray[i].transparent);
    bmd.setPixels(saveArray[i].bounds, saveArray[i].imgBytes);

    var bitmap:Bitmap = new Bitmap(bmd);

    //instead of passing in a file to your Iconn class, tweak it so you pass in a bitmap:
    var icon:Iconn = new Iconn(bitmap);

    //do what you need to do with he icon
}

Upvotes: 2

Related Questions