Titanium for iOS: Quick Profiling Example Using Xcode’s Instruments

One thing that, for now, sucks about Unity3D for iOS is that there seems to be no easy way to use a Profiler on your Unity generated .ipa file (am I wrong?). There’s progress on the Android side with this with official profiling support in Unity 4.0. While you can’t easily do 3D gaming using Titanium, you can use Xcode’s Instruments to profile your code to make sure there’re no memory leaks.

Titanium’s docs have a video on how to profile using Instruments. Here’s a simplified example .js file loaded into app.js, using the Single View application template in Titanium 2.x:

module.exports = function ApplicationWindow() {
	
	//load component dependencies
	var FirstPage = require('/ui/FirstPageView');
	var currentPg;

    //create component instance
	var self = Ti.UI.createWindow({
		layout: 'composite',
		width: Ti.UI.FILL,
		height: Ti.UI.FILL,
		backgroundColor:'#ffffff',
		navBarHidden:true,
		exitOnClose:true
	});

    currentPg = new FirstView(self);
    self.add(currentPg); 
   
    //will result in a memory leak that will show up as forever incrementing TiUIViewProxy instances in Instruments > Leaks under the "# Living" column 
	self.addEventListener('showSecondPage', function(evt){
		var SecondView = require('/ui/SecondPageView');
		self.remove(currentPg);
		currentPg = null;
		currentPg = new SecondView();		
		self.add(currentPg);	
	});

    return self;
}   

The above code would result in numerous leaks related to various subviews that exist whatever view is currently represented by the currentPg variable (FirstPageView or SecondPageView, depending on which event was fired). In my case, I profiled my app via Xcode’s Instruments, as directed here, and saw the TiUIViewProxy object incrementing forever, each time I went back to a particular page. It never moved from the
“# Living” to the “# Transitory” column.

The fix is fairly simple. I had to run a loop to setting all of currentPg’s subviews to null, “currentPg.children[i] = null”:

...
   //leak free version: 
	self.addEventListener('showSecondPageVersion2', function(evt){
		
           //clean up all subviews of currPage view (or app will get slower the longer you use it)		
		for(var i=0, l=currentPg.children.length; i<l; i++) {
			currentPg.children[i] = null;
		}

           var SecondView = require('/ui/SecondPageView');
		self.remove(currPage);
		currentPg = null;
		currentPg = new SecondView();		
		self.add(currentPg);	
	});
	...

You can improve the above code by adding a destroy() method to both FirstPageView.js and SecondPageViewjs and instead of using a loop in ApplicationWindow’s event listener just do currentPg.destroy().

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s