Problem
A CommonJS (JavaScript) module which is require()d by a url-based Window (a window created with the 'url' property) from inside of that window's 'open' event tries to access Ti.Network.online, but instead a runtime error is produced:
[ERROR] Script Error = Result of expression 'Ti.Network' [undefined] is not an object.
Please see the attached project (code repeated at the bottom of this description). It's a 5-step process to expose this error. The attached code has been minimized down from an actual project, so while it may look weird and seem to contain unnecessary steps, keep in mind that this is an excerpt from a real project with a real problem. I have reduced it down to the bare minimum necessary to reproduce the problem.
The normal workaround of adding a reference to "Ti.Network" in app.js does *not work* in this case.
Another problem that is evident in the example:
- In app.js, you shouldn't have to reference "Ti.App" to get past the use of Ti.App in deep.js, but without that line in app.js, you get the same "undefined" error on Ti.App.
The problem does *not occur on Android*...the app works fine.
Steps to Reproduce
- Unzip the attached project and run it to the iPhone simulator.
- Look at the console log.
- Right after "** trying Network", you will see this error
[ERROR] Script Error = Result of expression 'Ti.Network' [undefined] is not an object.
Expected Result
The app should run without error and give the console message "** Network is there!".
Testcase Code
var Sequencer=require('Sequencer');
Sequencer.SetML('deep',require('deep'));
Ti.App; // without this here, the Ti.App in deep.js crashes.
Ti.Network; // this workaround doesn't work.
var w1=Ti.UI.createWindow({url:'win1.js'});
w1.Sequencer=Sequencer;
w1.open();
Ti.API.info('** Loading Sequencer');
exports.ML={};
exports.SetML=function(Prop,Val)
{
exports.ML[Prop]=Val;
};
exports.GetML=function()
{
return exports.ML;
};
exports.RegisterWindowLoadEvent=function(TheWindow,OnLoadEvent)
{
Ti.App.CurrentWindow=TheWindow;
Ti.App.CurrentWindow.addEventListener('open',OnLoadEvent);
};
var Sequencer=Ti.UI.currentWindow.Sequencer;
deep=Sequencer.GetML().deep;
deep.RegisterWindowLoadEvent(Ti.UI.currentWindow,MainWinLoad);
function MainWinLoad()
{
Ti.API.info('** MainWinLoad');
Ti.API.info('** step 1');
var Killer=require('win2');
Ti.API.info('** step 2');
}
Ti.API.info('** trying Network');
if (Ti.Network.online)
Ti.API.info('** Network is there!');
Ti.API.info('** done trying Network');
If only all tickets were as well defined as this! Thank you, Shawn, I have escalated it immediately. :)
Thanks, Paul. It took me 1 whole work day to reduce this down to a small reproducable case from the actual project...it gave me one hell of a headache.
Note that the following version of
win1
*does* work, for the same reasons that the aboveapp.js
does (namely, it preloads the module into the right context):The problem is that the require()d module has its *page* in the context in which it was evaluated, which in this case, is always
app.js
. But the module is *executed* inwin1.js
and that's where the discrepancy comes from. This can only really be resolved by moving to single context, either within the app or changing the iOS infrastructure. Currently there is still the restriction that modules must be require()ed in the context in which they are evaluated.Issue reproduces Tested with Titanium Studio, build: 3.0.1.201212181159 Titanium SDK version: 3.1.0 Titanium SDK version: 3.0.2 iOS iPhone Simulator: iOS SDK version: 6.0
url-based window is no longer supported