The problem
Well, I don't know how to explain the problem, or what precisely is causing it ... so it's the best if I just jump to example. :D
Test case
var i = 0;
var win = {
backgroundColor: '#000',
__TiElement: null,
__getTiElement: function() {
if (!this.__TiElement) {
this.__TiElement = Ti.UI.createWindow(this);
}
return this.__TiElement;
},
open: function() {
Ti.API.info(i++);
this.__getTiElement().open();
}
};
win.open();
Run this example, and you should get infinite loop (see in DDMS, i goes from 0 to infinity).
As I said, I'm not sure what's causing the problem, but it seems that "this" value is somehow set to wrong value (TiUIWindow because "win" and that causes infinite loop).
The problem can be solved if non-enumerable properties are used (by using "Object.defineProperty").
The issue does not exist on iOS.
infinite loop exists Issue reproduces with Titanium Studio, build: 3.0.1.201212181159 Titanium SDK version: 3.1.0 (03/11/13 15:43 0c88429) Titanium SDK version: 3.0.2 (02/07/13 16:46 a4def81) Device: Samsung galaxy s duos Android version: 4.0.4 jithinpv
By giving 'this' to the createWindow, the execution context is set to 'this' which is the 'win'. so calling 'open' on the __TiElement actually calls the win.open. The behavior can be reproduced in a standalone javascript by replacing Ti.UI.createWindow(this) with 'new Object(this)' and replacing Ti.API.info with 'alert'.
Hi Sunila. That is not the same thing. "win.open" is different function from "TiWindow.open" (at least it should be). Your explanation of the cause of infinite loop could be right, but the problem still exists (that is, it should not happen). The same thing works on iOS - how come? ;)
In the above example, win.open() does NOT set the this binding to the open window, or global object, or module object (if one exists). The this binding is set to the object "win", just as you would expect. At least that is what should happen according to the ECMAScript 5 spec. This is definitely a bug in Android. I'm reopening it. If whoever works on this bug doesn't understand the details of how the this pointer is set in a function call, then come talk to me. FWIW the way that the this pointer is set in JavaScript calls is somewhat simple and _completely_ not what you would expect it to be.
Looks like a JS implementation bug.
Man is this an oldie. Anyhow, I believe this is because Android is applying
this
to the window proxy it generates (like it applies any supplied properties, not as the context to execute under) - therefore what happens is that the window instance has it'sopen
property (the native one we supply to actually open a window) replaced by the wrapper (win
object here)open
function. So calling open() on the window proxy is going to result in an infinite loop. This actually relates to TIMOB-5818 in that I believe this is a result of Android and iOS having different property attributes on that open method. iOS defines The open method as not being writable which is why the wrapper can't overwrite the native method. Android gives this for the property descriptor:While iOS gives:
(And will return that for made up properties on proxies that don't actually exist!)