How to make iPhone apps and influence people

Musings on the iOS development process

Profiling PHP Apps on OSX 10.9 with Xdebug and Kcachegrind

It's straight forward to generate Xdebug profiler output and visualise the bottlenecks associated with running any request that's run through the PHP stack.

Here's how you'd install PHP, Xdebug and Kcachegrind (qcachegrind) on OSX 10.9 Mavericks and get some in depth info on your php app.

qcachegrind on OSX 10.9 Mavericks

Install Homebrew

Make sure you have homebrew installed correctly.

The main thing to remember is to add /usr/local/ to your shell's $PATH. Often it's best to have it first so it overloads the system's default applications. brew doctor will complain if this isn't the case.

Add PHP Packages to Homebrew

PHP packages of OSX are not available to homebrew by default. The homebrew-php repository is the source of truth for PHP related recepies.

The homebrew-php README is verbose, on Mavericks you only need to run the following:

brew tap homebrew/dupes
brew tap homebrew/versions
brew tap josegonzalez/homebrew-php

This will give you access to all the php specific formulas.

Install PHP

Install PHP 5.3.x with the following commands:

brew install php53

Once installation is complete the formula tells you what to add to your httpd.conf to run the libphp5.so. Take note of the location of the php.ini file. The system default location is /etc/php.ini.default.

You can get back to the post-install info of any homebrew package with brew info php53.

# To enable PHP in Apache add the following to httpd.conf and restart Apache:
#    LoadModule php5_module    /usr/local/opt/php53/libexec/apache2/libphp5.so
#
# The php.ini file can be found in:
#    /usr/local/etc/php/5.3/php.ini

Open your apache config at /etc/apache2/httpd.conf and replace the existing (possibly commented out) LoadModule php5_module line with the LoadModule line from above.

Restart the apache process with:

sudo apachectl restart

Notes

I like to add index.php as a DirectoryIndex option. Find the <IfModule dir_module> section of the apache config and add index.php after index.html.

<IfModule dir_module>
    DirectoryIndex index.html index.php
</IfModule>

The arguments passed to the PHP compiler are visible in abstract-php.rb once you have everything running within apache the same variables are shown at the top of the phpinfo(); output under Configure Command.

The relevant options that will pick up the not-yet-installed XDebug config file and the php.ini file are:

def install_args
    args = [
    # ...
    "--with-config-file-path=#{config_path}",
    "--with-config-file-scan-dir=#{config_path}/conf.d",
    # ...
    ]

Install Xdebug

Install the appropriate Xdebug version for php5.3

brew install php53-xdebug

The notes from the installation mention the location of the Xdebug config file.

# To finish installing xdebug for PHP 5.3:
#  * /usr/local/etc/php/5.3/conf.d/ext-xdebug.ini was created,
#    do not forget to remove it upon extension removal.

Restart apache and load up a phpinfo(); page and you should see references to Xdebug.

Configure Xdebug to Generate Profile Data

All Xdebug options are well documented, below are a minimum set of options to get profile data written.

Open the generated ext-xdebug.ini and three configuration options profiler_enable, profiler_output_dir and profiler_output_name.

[xdebug]
zend_extension="/usr/local/Cellar/php53-xdebug/2.2.3/xdebug.so"

xdebug.profiler_enable = 1
xdebug.profiler_output_dir = /Library/WebServer/xdebug-profiler
xdebug.profiler_output_name = "callgrind.%R.%t"
  • profiler_output_dir - can be any directory, but it must be writable by the httpd process that runs under the wheel user on OSX systems. By default /Library/WebServer is not writable by many users; so pick your directory appropriately.
  • profiler_output_name - this option can be a format of your choice, the line above will produce files based on the URL, suffixed by a timestamp (callgrind._bh_apiv1_cafes_371_json.1394929295)

When you change these settings, restart apache and the changes should be visible in phpinfo().

If you're not seeing logs straight away, it's more than likely a file permissions issue on the output directory.

Visualise Profile Data

The preferred way to install kcachegrind on OSX is to install qcachegrind and AppViz. Both components can be installed with homebrew.

Underneath the hood qcachegrind uses graphviz's dot application to generate the graphs. dot will be available to qcachegrind if you've setup your $PATH correctly above.

brew install qcachegrind
brew install graphviz

After installation you should have qcachegrind in your path and you can launch it with the profile files as the first argument.

qcachegrind callgrind._bh_apiv1_cafes_371_json.1394929295

The absolute worst misuses of localised strings

As a followup to posting my Localising Cocoa Apps talk I thought I'd outline some of my favourite localised string failures.

The "I heard literal strings in code are bad" kind of localisation

NSLocalizedString(@"Next", @"");
NSLocalizedString(@"Next", nil);

The "WTF is the comment for anyway" kind of localisation

NSLocalizedString(@"Next", @"Next");

The "out of sight out of mind" kind of localisation

#define MYBadCompanyLocalizedString(key) NSLocalizedString((key), @"")

Yes, that's redefining the macro to hide the comment...

The "entire book as a key" kind of localisation

NSLocalizedString(@"In order to determine your location, location services must be turned on in settings", @"In order to determine your location, location services must be turned on in settings");

The "key can be anything but I know what it is" kind of localisation

NSString *aStringFromAPI = [response objectForKey:@"next-title"];
NSLocalizedString(aStringFromAPI, @"api resposne for `next`");

The grey area

Duplicating keys

This is in the grey area because good distinct comments can make duplicating keys manageable as good comments show you the key's appearances in your app in the .strings file.

NSLocalizedString(@"Next", @"RootViewController 'next' button title");
NSLocalizedString(@"Next", @"DetailViewController 'next page' button title");

//Localizable.strings
// DetailViewController 'next page' button title
// RootViewController 'next' button title
"Next" = "Next";
  • genstrings will warn you about duplicate keys
  • Bad/stupid/empty comments make this a bad offender
  • keys with nil or @"" comments aren't picked up as duplicate

Using localised strings in format strings

This is in the grey area because it's inflexible and implies a structure, but can be okay for small strings. Often you should consider NSNumberFormatter for numbers

button.titleLabel.text = [NSString stringWithFormat:@"4 %@, 3 %@", 
                          NSLocalizedString(@"pineapples",@"plural pineapples"),
                          NSLocalizedString(@"pears",@"plural pears")];

Localising the format string too

This is in the grey area because at this point we've got localised pieces everywhere. But it's good that you're trying though...

button.titleLabel.text = [NSLocalizedString stringWithFormat:
                          NSLocalizedString(@"4 %@, 3 %@", @"fruit quantities format string"),
                          NSLocalizedString(@"pineapples",@"plural pineapples"),
                          NSLocalizedString(@"pears",@"plural pears")];

Localising Cocoa Apps - Melbourne Cocoaheads August 2012

/* No comment provided by engineer. */
"Next" = "Next";

If your Localizable.strings file looks like this then you're probably doing it wrong...

Back in August I presented some best practices for localising your cocoa apps. The presentation centred around my experiences localising my own apps and the realestate.com.au app. I highlighted how using NSLocalizedString properly (or it's more useful cousin NSLocalizedStringFromTable) can make localisation a lot easier and logical.

Localising Cocoa Apps - Melbourne Cocoaheads August 2012

The first part of the presentation touched on something most people in the audience could relate too... the most notorious misuses of NSLocalizedString that I've seen.

I then went onto explain how NSLocalizedString works.

Towards the end I touched on a custom implementation of NSLocalizedString I had been working on aptly named JCLocalizedString that had a compatible interface with NSLocalizedString but would allow switching the active localisation at run time. JCLocalizedString exists on github in it's early stages.

The presentation slides are up on github and the video is on vimeo. The presentation notes are included with the slides and may be a good reference.

Localising iOS Apps - Jesse Collis from Melbourne Cocoaheads on Vimeo.

'Obsidian Code' Xcode Theme

I made some adjustments to an Xcode theme that I've been using for the last twelve months or so.

Obsidian Code' Xcode Theme

Check out the gist

Introducing JCTiledScrollView

JCTiledScrollView

To coincide with my February 2012 Cocoaheads presentation I have open sourced a component named JCTiledScrollView.

JCTiledScrollView is a set of classes that wrap UIScrollView and CATiledLayer. The project to simplify displaying large images and PDFs at multiple zoom scales. As the project evolves it's moving towards becoming a fully featured custom map view replacement with gestures and annotations.

Check out JCTiledScrollView on github.

CATiledLayer - Melbourne Cocoaheads February 2012

I put my hand up to do a talk at the February 2012 Melbourne Cocoaheads meet up on CATiledLayer. It was a great start to the year with an attendance of about 80 people at RMIT in the CBD.

My presentation was a reflection on my own experiences implementing a CATiledLayer backed UIScrollView, highlighting some of finer points of that didn't seem immediately obvious. During the presentation I introduced the a new open source project JCTiledScrollView that hopes to be a best case implementation of a CATiledLayer backed scroll view.

The keynote presentation and presentation outline are available on github. A video of the presentation is up on Vimeo.

Photo by Jeff Tan-Ang

CATiled Layer - Jesse Collis from Melbourne Cocoaheads on Vimeo.

Realestate.com.au iPad app goes live

It's been a number of months and some incredibly late nights in the making but the new realestate.com.a iPad App finally went live in the App Store last Friday, August 12. I was lucky enough to be able to give a demo of the app the night before release at the August Melbourne Cocoaheads meeting to one of the largest crowds to date!

I joined the REA Group mobile team back in March 2011 to help with the continuing development of their iPhone app, and after a UI uplift release for the iPhone we started working on a universal iPad app. After some hiccups along the way, we managed to deliver a brilliant looking, stable app that I'm really proud to have worked on. I'd say it's reset the bar for iOS property apps and is streets above the competition.

The REA Mobile team is lead by Kevin O'Neill (@kevinoneill), second chaired by Luke Cunningham (@icaruswings) and backed up by Steve Hollaway, Ben Thomas, Mike Rowe, Myles Abbot, Mujtaba Hussain and myself.

Some awesome technical bits / features of the app include:

  • Custom forms (IBAForms) for advanced property searches.
  • A gorgeous custom UI including the little bits that are really hard to customise.
  • Custom map callouts are really hard to customise.
  • It's a true universal app it has a shared underlying code base and consistent behaviour, look and feel.
  • It rotates, and it rotates like a boss. Rotate it, and see it resize itself without any of that crappy UI flickering you see elsewhere.
  • Swishy tap, pan and swipe gesture recognisers all over the place make interactions really fluid.
  • It's damn fast with it's own purpose built back end.
  • It's stable. We tested the crap out of this app!
  • It caches images and searches and other things;  it also behaves nicely when errors occur.
  • It's using the latest iOS 4+ technology and minimal amounts of old legacy code.
  • It leverages/wrangles a handful of awesome open source frameworks.
  • It sets the bar for it's category in mobile property apps.

The realestate.com.au iPad app &quot;Money Shot&quot; as we call it.

Custom callouts are one of the hard things to customise

So yeah ! If you haven't already - check it out on iTunes -> Realestate.com.au in iTunes

'Epic refactorings' - Melbourne Cocoaheads June 2011

Luke Cunningham (@icaruswings) and I presented a talk at the June 2011 Cocoaheads meet up titled "Epic refactorings and patterns to make your code awesome!".

Luke and Jesse's lightbulb moment

The topic was inspired by a number of design patterns we employed while developing the new realestate.com.au iPad application. We highlighted some of shortcomings we found with UIViewController and demonstrated our end result - ViewCoordinator

The book highlighted in the presentation is Agile Software Development. Principles, Patterns, and Practices by Bob Martin. The two design patterns we highlight form the book were single responsibility and Interface segregation.

Melbourne Cocoaheads 06/2011 - Talk 2 - Luke Cunningham & Jesse Collis from Oliver Jones on Vimeo.

The slides are available on Slide Share.

Note: the video's audio is quite average.

Attending: WWDC 2011 and Swipe Conference

Just a quick post to highlight some upcoming events I'm getting excited about.

If you're reading this and attending WWDC or Swipe Conference then hit me up on Twitter and we'll coordinate beers.

WWDC 2011 June 6-10 2011

First up is WWDC 2011 in San Francisco. - I didn't go last year and this year I'm flying up along side a handful of Melbourne iOS developers from the Melbourne Cocoaheads group and the Itty Bitty Apps guys, Sean Woodhouse and Oliver Jones. There's a Pre-WWDC catch up in Richmond/Cremorne in Melbourne on 1/6/11 being organised by Intunity and I will be attending that too.

Swipe Conference 2011

Later in the year is Swipe Conference (swipeconference.com.au@swipeconf), September 5 - 7 in Melbourne is the next big thing for iOS Developers and looking at the line up it's going to be a great three days. I'm hoping it brings in the iOS developers from near and far that have yet to turn up at a Cocoaheads meet - there's a lot of developers out there.

I'm also attending TEDxSydney on the 28th of May, but since I missed out on a proper ticket I'll be hanging out out the front all day like I did last year.