Reputation: 1049
I've seen the error before, usually when we're trying to call a constructor for an object that the interpreter hasn't seen yet. Most likely a dynamic attempt at instantiation. However, I'm currently experiencing the error on a line of execution on Android devices only.
See the guilty function below -
public class XMLBuilder
{
private var elementClasses:Dictionary;
private var elements:Dictionary;
public function XMLBuilder()
{
elementClasses = new Dictionary();
elements = new Dictionary();
}
public function buildFromXML(xml:XML):void
{
elements = new Dictionary();
var element:StardustElement;
var node:XML;
for each (node in xml.*.*) {
//error thrown on line below//
element = StardustElement(new elementClasses[node.name()] ());
if (elements[node.@name] != undefined) {
throw new DuplicateElementNameError("Duplicate element name: " + node.@name, node.@name, elements[node.@name], element);
}
elements[[email protected]()] = element;
}
for each (node in xml.*.*) {
element = StardustElement(elements[[email protected]()]);
element.parseXML(node, this);
}
}
public function registerClass(elementClass:Class):void {
var element:StardustElement = StardustElement(new elementClass());
if (!element) {
throw new IllegalOperationError("The class is not a subclass of the StardustElement class.");
}
if (elementClasses[element.getXMLTagName()] != undefined) {
throw new IllegalOperationError("This element class name is already registered: " + element.getXMLTagName());
}
elementClasses[element.getXMLTagName()] = elementClass;
}
}
Where the object 'elementClasses' is a dictionary that contains a set of Classes. (And In this case it does, i've checked while debugging on both iOS & Android). And where evaluating 'elementClasses[node.name()] is Class' returns true.
Does anybody know of any quirks in AIR that would cause this to happen on Android only? Or anything in this function that jumps-out?
Upvotes: 0
Views: 61
Reputation: 1049
So, in AS3 XML node.name() will return a QName
object. If you look at my registerClass(elementClass:Class)
, you will see that we're adding classes to the elementClasses
dictionary using element.getXMLTagName() which returns a String.
Now, apparently in AIR iOS if we attempt a lookup on someDict[someQName]
, someQName.toString() or some kind of cast is attempted.
Whereas in AIR Android, it would appear that it attempts to use the QName object itself as the key.
I would say that the Android implementation has the expected behaviour, but it's definitely fishy to me...
Fixed code below. node.name().localName
used instead essentially.
public function buildFromXML(xml:XML):void
{
elements = new Dictionary();
var element:StardustElement;
var node:XML;
for each (node in xml.*.*) {
element = StardustElement(new elementClasses[node.name().localName] ());
if (elements[node.@name] != undefined) {
throw new DuplicateElementNameError("Duplicate element name: " + node.@name, node.@name, elements[node.@name], element);
}
elements[[email protected]()] = element;
}
for each (node in xml.*.*) {
element = StardustElement(elements[[email protected]()]);
element.parseXML(node, this);
}
}
public function registerClass(elementClass:Class):void {
var element:StardustElement = StardustElement(new elementClass());
if (!element) {
throw new IllegalOperationError("The class is not a subclass of the StardustElement class.");
}
if (elementClasses[element.getXMLTagName()] != undefined) {
throw new IllegalOperationError("This element class name is already registered: " + element.getXMLTagName());
}
elementClasses[element.getXMLTagName()] = elementClass;
}
Upvotes: 1