First a PSA: Older versions of Apple’s Application Loader have been reported to cause problems on app submission related to icon sizes. Updating to the latest app loader resolves the issue. Related Q&A post here.

The following is the first in a series of Friday blog posts covering advanced topics and Titanium development best practices.

If you’ve followed the developer blog and read through our documentation out on the wiki, you’ve probably come across the phrase “proxy object” on a few occasions. Basically, a proxy is a special JavaScript object which is a stand-in for a corresponding object in native code (on iOS or Android – this magic layer is not needed on mobile web).

Any time you are interacting with a function or property in the Ti.* JavaScript namespace, or dealing with an object you got back from a function in this namespace, that object is a proxy of some type. In order to facilitate communication “over the bridge” from the JavaScript context to native code, these proxy objects have been instrumented with special behavior which allows native code (Java, C, or Objective-C) to intercept assignments and function calls to these objects. This model of interaction is what allows developers to essentially write native code in JavaScript, and makes Titanium distinct from many other other cross-platform tools.

Proxies Are Special

As a user of the platform, though, it is helpful to understand a few things about these objects. At least in the 1.x and probably for most of the 2.x timeframe, proxy objects won’t always play by the rules of JavaScript. Let’s take a look at some areas where the rules of JavaScript get bent or broken.

Nested Objects

In a normal JavaScript object, you can set nested properties on objects (so long as those properties/objects exist), as in “meaning.of.life = 42;”. With proxies, this cannot be done. One notable place where you’ll run into this is with the “font” property of Labels. In the example below, the “l” object is a proxy, which should have a nested property font, and then fontSize associated with it. Trying to set the nested property fontSize directly does not work, but setting the entire font object to a new value does:

Overriding Properties

Another behavior of proxy objects is that the functions defined as the public interface of a proxy object (functions and properties Titanium expects to use) cannot be overridden as they could be with typical JavaScript objects. The following is legal JavaScript code:

But when run, you’ll notice that since “open” is a function that is part of the proxy’s public interface, the “built in” open functionality remains, even though we think we’ve overridden it:

Getters and Setters

Certain function names also have magic associated with them. Any function prefixed with “get” or “set” will be delegated to native code, so any custom getters or setters you’d like to set up on a proxy will be ignored:

.apply and .call

For instance, normally you can call any Function in JavaScript using .apply or .call, since functions are first class objects. With Titanium proxy objects, because of their special plumbing, you’re not able to do this out of the box. The following is code that should be rational:

Wrapping Proxies

Occasionally this behavior becomes annoying, because we expect to be able to use all the JavaScript tricks up our sleeves on the objects which are part of or produced by the Ti.* namespace. When dealing with a proxy directly presents a problem, a common approach is to wrap a proxy object in a regular JavaScript object with no link to an object in “native land”. It can be as simple as the following example, which could be placed at the root of a Titanium project directory:

Using this technique, you can avoid the special behavior of proxies when working with them directly is a pain in your neck.

Summary

A proxy object is the bridge that empowers you to write a native app in JavaScript. However, they do have some special rules applied to them. The big ones to watch out for are:

Can’t set properties of nested objects

Unable to override properties in the proxy’s public API

Functions prefixed with “get” and “set” are intercepted

.call and .apply don’t work on proxy objects

When this behavior presents a problem, it becomes useful to wrap a proxy object in a plain JavaScript object, which will “play by the rules” of JavaScript. Next week, we’ll be looking at a more complex way to use this object wrapper technique to build custom components with CommonJS modules. See you next time!

6 Comments

Really glad you guys have blogged about this. I’ve spent hours in the past tearing my hair out trying to do things with Ti Proxy objects. One of the only areas I’ve really found confusing in this otherwise fab product. Thought it might be useful to share the method I use in my TI apps for creating my own objects which extend Ti Proxy objects:

// You can’t attach complex members such as objects to Ti Proxy objects
// But by getting the MyVars object, we can attach anything we like since it is a real JS object
// So we use the ‘myVars’ a bit like a surrogate for stuff we’d normally attach using ‘this’.
var myVars = oTi.gtMyVars();
myVars.label = Ti.UI.createLabel({bottom: ‘50%’, backgroundColor: ‘blue’, textAlign: ‘center’});

// We can treat the Ti object as a normal Ti object, e.g. add a label
oTi.add(myVars.label);

// Return the Ti object as our object
return oTi;
};

// Set the label text for our ‘mywin’ object (NB: We use prefix ‘st’ rather than ‘set’ delibrately)
mywin.prototype.stLabelText = function(txt)
{
// We just need to get the ‘myVars’ object and we are in business
var myVars = this.gtMyVars();
myVars.label.text = txt;
};

I think the biggest ones to look out for here are the getters and setters or rather the inability to create them.

Not bring able to use apply or call is understandable, these are ‘magic functions’ and apply and call are special in their own right. I suppose deep nesting properties is handled a little strange but you’ll work out whats wrong with implementing them pretty quickly.

Compare this to trying to debug a function which looks fine and where it’s neighbouring code works. This can be a nightmare to debug and incredibly frustrating for that first time when you realise the problem is its name starts with ‘set’ or ‘get’. Renaming a function to see if it works will be the last thing you’ll think to do.

It’s not an obvious problem and having to know not to name functions with ‘set’ or ‘get’ in order to avoid these headaches is in my opinion not a good enough solution.

@Conor: Kevin alluded to it in this article, but we are planning on showing some techniques for wrapping your proxy objects, thereby all but eliminating your need to be aware of any special rules for proxies. Stay tuned for that.

Kevin Whinnery

Posted February 6, 2012 @ 7:06 am

@Connor agreed, it’s not acceptable. It’s a large refactor on how we’ve implemented proxies, but we plan on getting to the point where every object is wrapped as soon as possible in the core.

Ivan Skugor

Posted March 23, 2012 @ 4:15 am

This approach is nice, but it has one flaw. This wrappers can’t be used as prototype objects because Titanium component is created in function constructor.

For example:

function ExtendedWindow() {

}

ExtendedWindow.prototype = new WrappedWindow();

“ExtendedWindow” instances won’t create new instances of Titanium Window and therefore that won’t work if extension is made this way. One way to avoid problem is to call parent’s function constructor every time wrapper is extended. But that is a hack that would eventually impact performance. One guy rephrased this problem by calling “init” function that creates Titanium component from function constructor. That solution is better, but it’s against DRY principles (in every function constructor, same line is present “this.init()”).