Saturday, July 2, 2011

Persisting typed singleton objects in Flex Mobile via PersistenceManager

I recently ran into a real mess when trying to persist a typed singleton object in a Flex Mobile application via the PersistenceManager class.

DevGirl Holly Schinsky has a great blog post on managing data in a Flex Mobile application, and I was specifically using her instructions on persisting typed objects. The basics are this:

1.) Register the class alias"person",model.Person);

2.) Get an instance of the PersistenceManager class
var persistenceManager : PersistenceManager = new PersistenceManager();

3.) Save the object to be persisted
persistenceManager.setProperty("savedData", _personInstance);;

4.) Re-load the object at a later time

Everything works totally fine UNLESS the object you're persisting has a hidden internal class - a class who's scope is internal to the model object class itself. This is often the case for singleton classes in AS3 - since there's no way to make a private constructor the best-practice for singletons in AS3 is to make the constructor take an instance of an internal class object so that no external classes can call the constructor.

I suspect the error is during de-serialization - since the serializer can't make an instance of your singleton model's internal class, it can't make the model class itself at all, and de-serialization fails.

For now I'm just removing the internal classes from my singleton. It means it's no longer really secure, but I'll take the easy data persistence and built-in serialization of the PersistenceManager over having to do the serializing/de-serializing myself.

I suspect this would be an issue with any AMF serialization in Flash - I bet these types of locked singleton's can't be persisted across the client/server or to a regular LSO or anything like that either.


sebestenyb said...

Maybe the problem here is that to make Flash to deserialize your custom data, your custom class's constructor arguments must have a default value, since the Flash Player first create an instance of the class, and then calls the readExternal method on it to restore it's state.

If your constructor argument has no default value, it will fail to insatiate.

How about trying
public function Person( enforcer:SingletonEnforcer = null )

RJ said...

Seb - I agree that a default variable would probably work, but what's the point? A default variable means that anyone can call the singleton's constructor. Preventing this is the explicit purpose of the locking class. I don't need that locking class for anything else - If I'm going to give it a default value I might as well not have it in there at all. :)