Excessive Data Usage with iPhone 4S / iOS5

Got a new iPhone 4S or recently upgraded your iPhone 4 or 3GS to IOS5 and noticing unusually high cellular data usage? Are you close to exceeding your data usage limit when you never have before? Have you already exceeded it? You are not alone.

My wife recently traded in her old iPhone 3G for a shiny new iPhone 4S, and within 10 days had exceeded her 200MB AT&T data plan limit when she has never exceeded it before. So what gives? It’s a new phone, and Siri does transmit voice data back to Apple’s servers, but could that really have caused the usage? Continue reading

How to add Photos to the iPhone Simulator

Building an app that needs to access the photo library but don’t have any photos in the iPhone simulator? No problem. Follow these simple steps to import photos into the iPhone Simulator:

  1. Open the iPhone Simulator
  2. Browse to the photo you want to put into the simulator (Finder or web browser)
  3. Click and drag the photo over the simulator window. A green "plus" icon should appear under your cursor with the simulator frame highlighted. Drop the photo.
  4. Mobile Safari should open on the simulator to the location of the image you just dragged and dropped over it
  5. Note that if the image you dropped is linked in a webpage, it will open the link instead of the image URL.
  6. Click the mouse down over the image and hold it until a popup window appears.
  7. Click "Save Image"

The photo will now reside in the "Saved Photos" album on the iPhone Simulator. Rince and repeat as many times as you need to get all your photos in the album.

Easier Titanium XHR and AJAX Requests

One question I see a lot on the Appcelerator Titanium Developer Q&A is how to perform AJAX requests and/or work with APIs, etc. There is a built-in way to do this with the Ti.Network.HTTPClient module that is pretty easy, but it does have a few drawbacks and “gotchas”, like executing the “success” event for ANY returned status code – even 500 errors. Since working with APIs is so common with mobile apps, I made a wrapper function modeled after jQuery’s $.ajax method that I use in all my apps. It shortens the syntax quite a bit and is much more familiar to those who are used to using jQuery.

The usage looks like this:

// Geocode input text location
app.utils.ajax({
     url: 'http://maps.googleapis.com/maps/api/geocode/json?address=' + txtLocation.value +'&region=us&sensor=true',
     method: 'get',
     success: function(xhr) {
         var data = JSON.parse(xhr.responseText);
         Ti.API.info(data);

         if("OK" == data.status) {
             var res = data.results[0];
             if(res) {
                 alert("Location: " + res.geometry.location.lat + ', ' + res.geometry.location.lng);
             }
             // Do something with coordinates
         } else {
             Ti.UI.createAlertDialog({
                 title: 'Geocode Error',
                 message: 'Unable to geocode location input'
             }).show();
         }
     },
     error: function(xhr) {
         Ti.UI.createAlertDialog({
             title: 'Geocode Error',
             message: 'No location matches found. Please try something else.'
         }).show();
     }
});

And the actual code for the utility function:

/**  * Application Utilities and Helper Methods  **/
(function(_app) {
     _app.utils = {};

     // AJAX method that mimmicks jQuery's
     _app.utils.ajax = function(_props) {
          // Merge with default props
         var o = _app.combine({
             method: 'GET',
             url: null,
             data: false,
             contentType: 'application/json',

             // Ti API Options
             async: true,
             autoEncodeUrl: true,

             // Callbacks
             success: null,
             error: null,
             beforeSend: null,
             complete: null
         }, _props);

         Ti.API.info("XHR " + o.method + ": \n'" + o.url + "'...");
         var xhr = Ti.Network.createHTTPClient({
             autoEncodeUrl: o.autoEncodeUrl,
             async: o.async
         });

         // URL
         xhr.open(o.method, o.url);

         // Request header
         xhr.setRequestHeader('Content-Type', o.contentType);

         if(o.beforeSend) {
             o.beforeSend(xhr);
         }

         // Errors
         xhr.setTimeout(10000);
         xhr.onerror = function() {
             Ti.API.info('XHR "onerror" ['+this.status+']: '+this.responseText+'');
             if(null !== o.error) {
                 return o.error(this);
             }
         };

         // Success
         xhr.onload = function() {
             // Log
             Ti.API.info('XHR "onload" ['+this.status+']: '+this.responseText+'');

             // Success = 1xx or 2xx (3xx = redirect)
             if(this.status < 400) {
                 try {
                     if(null !== o.success) {
                         return o.success(this);
                     }
                 } catch(e) {
                     Ti.API.info('XHR success function threw Exception: ' + e + '');
                     return;
                 }

             // Error = 4xx or 5xx
             } else {
                 Ti.API.info('XHR error ['+this.status+']: '+this.responseText+'');
                 if(null !== o.error) {
                     return o.error(this);
                 }
             }
         };

         // Send
         if(o.data) {
             Ti.API.info(o.data);
             xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
             xhr.send(o.data);
         } else {
             xhr.send();
         }

         // Completed
         if(null !== o.complete) {
             return o.complete(this);
         }
     };

     // And it does depend on this code below to combine object properties:

     // Extend an object with the properties from another
     // (thanks Dojo - http://docs.dojocampus.org/dojo/mixin)
     var empty = {};
     function mixin(/*Object*/ target, /*Object*/ source){
         var name, s, i;
         for(name in source){
             s = source[name];
             if(!(name in target) || (target[name] !== s && (!(name in empty) || empty[name] !== s))){
                 target[name] = s;
             }
         }
         return target; // Object
     };
     _app.mixin = function(/*Object*/ obj, /*Object...*/ props){
         if(!obj){ obj = {}; }
         for(var i=1, l=arguments.length; i<l; i++){
             mixin(obj, arguments[i]);
         }         return obj; // Object
     };

     // Create a new object, combining the properties of the passed objects with the last arguments having
     // priority over the first ones
     _app.combine = function(/*Object*/ obj, /*Object...*/ props) {
         var newObj = {};
         for(var i=0, l=arguments.length; i<l; i++){
             mixin(newObj, arguments[i]);
         }
         return newObj;
     };
})(app);

The particular organization of this utilities file assumes that your app structure follows the organization model shown in the Tweetanium example app (using the ‘app’ namespace within a single window context), but is easy to adapt if you are not.

Count the Number of Object keys/properties in Node.js

When using the excellent formidable library to handle file uploads, I needed to get a count of the number of files unloaded in a multi-part form. Javascript arrays have a .length property that you can use, but objects do not. I instinctively typed:files.length

Which returned undefined. So if there is no length property present, an easy way to count the number of keys or properties of an object in ES5-compliant javascript environments like Node.js is to use the Object prototype directly:

Object.keys(files).length

A little more typing, but it is fast, efficient, and most importantly: already built-in.

php|tek 2011

php|tek 2011 Speaker Chicago – May 24-27 php|tek in Chicago was fun as always. It is the best PHP conference I have ever been to, which makes sense, given that it is focused solely on PHP and surrounding technologies. The best thing about the conference is the community feeling in general. You get a real sense that everyone there really cares about PHP and is heavily invested in it, which is good for moving the whole language and ecosystem forward.

I myself gave two talks – one about Stackbox CMS, a new CMS project I have been working on, and one about Apppcelerator Titanium Mobile since I have been working with it a lot lately. The presentations are embedded below.

Continue reading

Titanium Mobile: How to Display an Image with Pinch-to-Zoom and Panning

There are many things that are not immediately obvious when working with Appcelerator’s Titanium platform. Displaying a large image with support for common gestures like pinch-to-zoom or panning around, for instance. If you are used to the Titanium platform and developing apps with it, you think it would be available in the events you can listen for – something like "twofingertouch" or similar that would have a dictionary of coordinates for each finger that is present on the screen.

is one of the most often posted questions in the Q&A section.

Android+iPhone SEO App

I just released a new iPhone SEO app and Android SEO app called SEMTab SEO Pro. The basic idea is to keep a list of domains saved, and check SEO/SEM stats like Google PageRank (PR), backlinks, Alexa rank, etc. and Social share information from Twitter, Facebook, and Delicious. more

ss1-listss2-webss3-social1

 

The first two pictures are of the iPhone app, and the last one is of the Android app. SEMTab SEO Pro was built with  Titanium using all native cross-platform UI controls, so it builds both the iPhone and Android app from a single codebase and a single development effort.

The nice thing about SEMTab is that it makes extensive use of Titanium’s event system to fire off simultaneous asynchronous HTTP requests to the various web services and APIs to fetch data about the current domain you are checking. This prevents the application from locking up while fetching rank or share information, and it prevents the HTTP requests from stacking up in a queue and waiting for the ones in front of it to finish. The end result is a pretty slick & simple SEO app that gets the results you want quickly, without feeling sluggish or unresponsive.

Check out SEMTab SEO Pro in the App Store or the Android Market when you get the chance — and don’t forget to leave some feedback with a rating.

Protected vs Private Scope: Arrogance, Fear, and Handcuffs

The age old private vs protected debate has been re-ignited in the PHP community recently following the decision of Doctrine2 and Symfony2 to make all class methods private until there is a very clear and proven reason to change them to protected or public. The intention is a good one – to ensure they are providing a clear and stable API through intentional and known extension points that they can better test and support. Fabien (the creator of Symfony) points to this benefit in an article of his own explaining the thinking behind the decision. The primary started point of Fabien’s article and the driving thought behind this whole change and philosophy is (emphasis his):

Having a few well defined extension points force the developer to extend your library the right way instead of hacking your code.

The problem is that this kind of thinking is a slippery slope that kills the spirit of programming. It alienates the more pragmatic developers within communities. Telling other developers that you are going to force them to work with your code in some pre-determined "right way" is an incredibly arrogant statement to make. more Instead of letting the codebase grow organically and be modified or extended at will, you handcuff developers and send them a different message. Allow me to re-phrase it using my own words:

I know the right way to use this code and I have thought of all the possible use cases. If you don’t agree, then you have to prove me wrong and wait until I either agree or figure out a better right way for you.

This is the real message developers hear when internal code is private scope or marked with the final keyword – a message that they have arbitrarily limited power and ability to make changes where they need to. But it doesn’t stop there.

When you take the position that all methods should be private unless proven otherwise, you plant a seed of fear in the developers that use your code. Fear that whenever they may have to veer off the beaten path to meet a project requirement they won’t be able to. Fear that they might miss deadlines waiting for the "right way"  to enable the functionality they need. Fear that they might have to modify or hack the actual file or class they need to change the behavior of to achieve the functionality they want within the project deadline because they are not able to extend it.

Using private scope removes the fun from programming and kills the hacking spirit by creating fear through the knowledge that you will not have the ability to make changes anywhere in the codebase you need to when you need to. You are no longer in control of your own code. You were forced to submit to a nanny state mentality by sacrificing your freedoms to modify the code for the promise of future stability and safety. That’s not a fun place to be when you’re on the receiving end, and it’s not a policy I would ever consider enforcing with my own code. I sincerely hope this line of thinking does not proliferate within the PHP community and infect other projects.

Self Employed

This post comes with a bit of a delay, as it is already three months into the year, but as of January 2011, I have been full time self-employed. I made the difficult decision to voluntarily leave an excellent job with Company52 at the beginning of the year to venture out on my own. Running  my own company with full-time focus has always been one of my dreams, and several side projects I have started and been involved with up until now have built up towards that goal.

There is a lot to consider in a decision like this, and I did not weigh it lightly. Somehow after running through all the options, now still seemed like the best time to take the leap. Here’s to a bright future in 2011 and beyond.