iPhone Development

Motivation for Converting from Subversion to Git

We’re in the process of converting to Git at work. We’ve been talking about doing this for quite awhile, but never really had a compelling reason to do so. Recently though, something happened that has given us that reason.

Many of our projects are done with teams in both Hyderabad and India. We refer to these as “hybrid” projects. In a recent hybrid project, the SVN repository contained a lot of large assets (movies, images, PSDs, etc). Unfortunately, the internet bandwidth in our India office has been pretty bad. This caused updates to/from the svn server to take a very long time. This by itself caused delays, due to the time it took to sync up at the beginning and end of each location’s workday.

But then we threw a real monkey wrench into the works by converting the project to “Branch Based Development”. BBD has become a best practice where I work. We use this term to mean that a branch is created for each and every development task, then the branch is merged back into trunk only after it has been completed, tested, and code reviewed. However, branching/merging in Subversion requires essentially downloading then uploading the entire branch/trunk. I’m probably oversimplifying this, but the result was that each task ended up incurring that long update delay. Often multiple tasks can be completed in a single day, so now instead of a single delay at the beginning or end of the day, we ended up having this delay multiple times per day. At its worst, we were looking a 1-2 hours of delay per task!

At that point, someone pointed out that had we been using Git, this would not have been a problem. Git is much smarter about its branching, and doesn’t require this full upload/download to the remote. Granted, better organization of our svn repositories could have alleviated much of this problem, but we recognized that for international development, a DVCS like Git would be valuable and improve productivity.

So we’re using Git now. My experience with Git has been pretty much limited to clicking on the “Clone in Mac” button on Github. So I needed to learn Git.

Luckily, lynda.com has a very nice Git Essential Training course by Kevin Skoglund. I just completed that course this morning, and I’m excited now to get started using Git.  I recommend that you checkout the lynda.com course if you are just getting started with Git also.

iOS Development on iPad

I’ve started looking at if/how to do iOS development on an actual iPad. I currently use an 11″ Macbook Air. It’s portable and powerful. But I find myself doing everything on the MBA instead of learning how to really use the iPad.

With that in mind, I’m trying to force myself into really using the iPad for everything. It’s clear that most things will be a snap (email, chat, conferencing, etc), but iOS development is a bit of a challenge.

A couple approaches appear obvious:

  1. Remote Desktop to a development system
  2. Edit on iPad, and use FTP/Dropbox/etc. to sync to a development system.
  3. Get Apple to recompile Xcode for iPad (or JetBrains to recompile AppCode for iPad).

The first option is fairly straight forward. Tools such as TeamViewer and PocketCloud make this fairly simple. The only trick here is to set the development system’s screen resolution to match the iPad. This eliminates the need to scroll over the viewport.

The second option is perhaps more interesting. It should have a definite performance advantages, but somewhat greater complexity. There are several blogs talking about using DropBox to expose files on the iPad, then using Textastic or Koder to do the editing.

Option 3 is of course Nirvana for this, but totally out of our control. Anyone from Apple or JetBrains listening?

Running a Jira server on Mac OSX

I’m currently using Jira at Mutual Mobile where I work, and I’m looking at using it with my hobby projects. It appears that this can be done very inexpensively if I host it myself on my Mac. I’d probably want to do that anyways, if not just from a learning perspective, but because of the cost ($70 one time cost for almost all the Atlassian apps):

  • Jira 10 users ($10 one time)
  • GreenHopper ($10)
  • Bonfire ($10)
  • Confluence ($10)
  • FishEye ($10)
  • Bamboo ($10)
  • Crucible ($10)
  • Jira Mobile Connect (free)
  • gliffy (free, $10 donation to requested)

I am choosing not to go with HipChat because I’m using Google+, nor Team Calendars because I’m using Google calendars for my simple needs.

Installing Jira on OSX

Installation on OS X is possible, although not officially supported by Atlassian.

  1. Identify $JAVA_HOME on your system. On my Mountain Lion system typing /usr/libexec/java_home results in /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home
  2. Ensure the $JAVA_HOME environment variable is set. Type “echo $JAVA_HOME”. It should display the path. If not, set it to do so. A good option  for Mountain Lion is to add it to the /etc/launchd.conf  by adding “setenv JAVA_HOME <path>”. If you’re not familiar with editing in the terminal, try “sudo nano /etc/launchd.conf”. Reboot, and verify that “$JAVA_HOME/bin/java -version” works.
  3. Purchase and download a copy of Standalone Jira, and extract the files. Put the files in a location of your choice. I chose my user folder /Users/ronlisle.
  4. Set JIRA_HOME
    In terminal, from the Jira home directory, run ./bin/config.sh.
    When prompted, enter a JIRA_HOME directory path.
    I chose to create a jiraHome directory in my Google Drive directory.
  5. Create a dedicated user to run Jira
    Open system preferences, select Users & Groups, click on + to create a “Jira” standard user.
  6. Start Jira
    In terminal from the Jira installation directory, ./bin/startup.sh
  7. Run the setup wizard
    Open a browser to “http://localhost:8080”

By default, the installation will use the built-in HSQL database. This is suitable for evaluation only. If you have a MySQL database available, then I recommend that you switch to it:

  1. Create an MySQL database user (eg. jiradbuser)
  2. Create an MySQL database (eg. jiradb)
  3. If needed, copy the MySQL JDBC driver.
    It wasn’t needed during my installation.
  4. Configure Jira to use the MySQL db (./bin/config.sh)

I tried using MySQL running on my host server, but switched to using MySQL running on my Mac because it is faster and it enables me to work completely offline. Whichever your choose, be sure to keep backups.

Installing Confluence on OSX

  1. Create a “confluence” directory in your User home directory.
  2. Download and extract the Confluence zip file to that confluence directory.
    At the time I did this, the current version is 4.3.2 so I named this ~/confluence/confluence-4.3.2
  3. Edit the ~/confluence/confluence-4.3.2/bin/setenv.sh to add the line (at the top):
    export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home
  4. Create a “data” directory in the confluence directory (~/confluence/data).
  5. Edit the …/confluence/confluence-4.3.2/confluence/WEB-INF/classes/confluence-init.properties file and replace the last line to indicate your install directory as follows:
  6. Change the port assignment for confluence so that it doesn’t conflict with Jira.
    Edit the conf/server.xml file to set Server port=8015 and Connector port=8090
  7. Create a local MySQL database and user:
    Create database confluence;
    grant all privileges on confluence.* to ‘confluenceuser’@’localhost’ identified by ‘confluencepass’;
  8. Start confluence by running bin/start-confluence.sh
  9. Open confluence by browsing to http://localhost:8090

Accessing private methods and properties in ObjC unit tests

I’ve seen quite a few questions posted on various programming websites asking about how to access a class’s private methods from a unit test file. In Objective-C there are several ways to do this:

  1. Use performSelector in the unit test to access private methods
  2. Use Key-Value Coding to access properties and iVars.
  3. Define the methods and properties in a class extension.

I really like the 3rd approach the best. In case you aren’t familiar with class extensions in Objective-C, these are also known as anonymous categories.  The following example shows a simple class definition and implementation that includes a class extension:

// ExampleClass.h
// Public header file
#import <Foundation/Foundation.h>
@interface ExampleClass : NSObject {
// Publicly exposed methods
- (void)exampleMethod;
// Publicly exposed properties
@property (nonatomic, retain) NSString * exampleProperty;
// ExampleClass.m 
// ExampleClass implementation 
#import "ExampleClass.h"   
@implementation ExampleClass 
// Properties 
@synthesize exampleProperty = exampleProperty_; 
// Methods 
- (int)exampleMethod {  
    // Do whatever this method needs to do... 
    return 3; 

In this example, I’ve defined a class with an exampleMethod and exampleProperty. Both of these are declared publicly and so can be accessed easily from a unit test file as shown below:

// ExampleClass.m
// ExampleClass unit tests
#import <SenTestingKit/SenTestingKit.h>
#import "ExampleClass.h"

@interface ExampleClassTests : SenTestCase {
@property (nonatomic, retain) ExampleClass * testClass;

@implementation ExampleClassTests
@synthesize testClass = testClass_;
-(void)testExampleMethodReturnValue {
    ExampleClass * ourClass = [[ExampleClass alloc]init];
    int returnValue = [ourClass exampleMethod];
    STAssertTrue( returnValue == 3, 
        @"Return value should have been 3 but was %d",returnValue);

Now, what if you wanted to keep exampleMethod private, and not expose it in the public ExampleClass.h header file? As mentioned above, the unit test could use performSelector to execute the method, but this approach is limited to passing a single argument and precludes letting the compiler check your parameters, etc.

A better way is to declare exampleMethod in a class extension, and put that class extension in a separate header file. This file can then be imported into both the ExampleClass implementation file as well as any unit test files that need to access exampleMethod. This class extension header file is shown below.

// ExampleClassExtension.h
// ExampleClass Class Extension
// Declare any private methods and properties in this file.
// #import this file into the implementation file and unit test files.
@interface ExampleClass ()
- (int)exampleMethod;

It’s just that simple. Using a class extension is considered a best practice for declaring your private methods and properties. Doing this makes it clear that these methods and properties are not intended for public use, otherwise they would be listed in the main header. But putting them in a class extension in a separate header file allows your unit tests to use them also. These methods and properties can be easily refactored, and will work correctly with autocompletion.

iOS Unit Testing

I’ve been knee-deep in iOS unit testing for the past few months. Xcode 4 has been a real blessing as well as a curse. Apple did a great job of integrating unit testing into Xcode 4, but so far has failed to provide much in the way of documentation. To make matters worse, things have changed drastically from Xcode 3. In the upcoming days and weeks I will be sharing what I’ve learned about unit testing in the new Xcode 4 environment.

Creating Icons for iPhone apps

As the number of devices support by iOS grows, the list of icons needed when submitting an iPhone app grows. Here’s a list of the icons and the default filenames that you’ll need:

Size Name Description
512×512 Whatever Used on app store
57×57 Icon.png Default icon for pre-iPhone4 devices (non-retina displays)
114×114 Icon@2x.png Icon for retina display devices
29×29 Icon-Small.png Small icon for use on non-retina displays
58×58 Icon-Small@2x.png Small icon for retina displays
72×72 Icon-72.png iPad icon
50×50 Icon-Small-50.png Icon displayed in search window

Note that the default filenames can be overridden with the info.plist icon-files entry.

The official list is on the Apple developer site: Technical Q&A QA1686.

An easy way to create all of these icons is to start with a 512×512 image, and then export it in each of the smaller sizes. I’m a Photoshop user, so I use ‘Save for Web & Devices’ in the File menu, but just about any image editor should have the ability to do this.

Xcode 4 Released

Woohoo! This week Xcode 4 was officially released. It took me several days to get it to downloaded since it is over 4 gigs, but once I did I really like what I see. It installed without problems, and I was able to open and update the Celestino app without problems.

Android Development

As part of my work at FanTrail, I am responsible for testing and creating the test automation for web services, iPhone applications, and soon Android applications.

So to prepare for Android testing, I’ve downloaded and begun playing with the Android SDK. Wow, guess what? It is also Eclipse based. So I simply added the Android Eclipse plug-in to my existing Zend Studio/Eclipse installation, and I was up and building test code in almost no time (Well, actually the download itself took the most time).

Now I’m having to brush off my Java skills, and I’m ready to dive in. I had initially resisted getting involved with Android for fear that it would interfere with my iPhone skills, but I’m rethinking that now. So maybe there are Celestino and/or Leander KOA Android apps in my future…

KOA iPhone App is finished

I’ve completed the KOA iPhone app. I will be finishing testing and submit to the App Store by the end of the week.

Leander KOA iPhone App

Now I am going to create a matching website that will provide the same functionality for those poor souls that do not own an iPhone. From my experience, about 90% of all KOA campers have computers. We currently hand out a local attraction pamphlet which lists local restaurants, stores, and services. But the space on the pamphlet is limited. Providing a website/iPhone app allows providing dynamic searching and sorting, allowing a larger list to be provided.

One really cool thing about the iPhone for this sort of application is the built-in location services (GPS). Not only can I provide a list of items sorted alphabetically or by location, but I can sort the list dynamically based on the users current location, not just the distance from the KOA.