by Derek Clarkson (d4rkf1br3 [at] gmail dot com)
It’s been a lot longer coming than I expected, but I’m releasing The Pieman , a command line driver program for Simon, my BDD framework for iOS. Using the Pieman you can now drive Simon BDD tests from the command line and therefore, from a Continuous Integration (CI) server. This means that iOS testing, especially interface testing can now be directly integrated into your build process.
The Pieman does a number of things. Firstly he’s capable of launching the iOS simulator and loading an app into it. This is nothing especially new. There are several launchers already. Waxsim being one that I got a lot of inspiration from when coding. Where the Pieman differs is that he can firstly close down any currently running simulators, reset the simulator and will close it down after the test run has completed.
Simon and the Pieman are more tightly coupled that in most frameworks currently available. The Pieman is launching and monitoring the simulator, and in addition both Simon and the Pieman are running embedded HTTP servers and talking to each other via REST calls. This allows the Pieman to known when Simon is ready to run tests, when each test has finished, when the run has finished and if Simon or the app hang, the Pieman knows through a separate heartbeat which is also being sent between them.
You can find out more in the Pieman’s doco
Posted on 24 October 2012, View commentsSome time ago I answered a question onStackOverFlow about the sizes and names of splash screens for iOS devices. Since then it regularly gets an up vote, I suspect from people looking for a good summary. However it is quite out of data as I’ve never gone back to visit it. So because of it’s popularity, I’ve decided to do and update and to copy the information here as well. So here goes (please let me know if there is missing or incorrect data here).
| iOS 3.1.3 Filename | Dimensions (Retina) |
Notes |
|---|---|---|
| Icon-Small(@2x).png | 29 × 29 (58 × 58) |
Settings/search icon. |
| iTunesArtwork(@2x) | 512 × 512 (1024 × 1024) |
Used for apps which being installed via adhoc distribution. The file must be a PNG file, but without a file extension. |
| iOS 3.1.3 Filename | Dimensions (Retina) |
Notes |
|---|---|---|
| Icon(@2x).png | 57 × 57 (114 × 114) |
Apps icon. Required. |
| iOS 3.1.3 Filename | Dimensions (Retina) |
Notes |
|---|---|---|
| Icon-72(@2x).png | 72 × 72 (144 × 144) |
Apps icon. Required. |
| Icon-Small-50(@2x).png | 50 × 50 (100 × 100) |
Search results icon. |
Just like icons, launch images are searched for based on the base name of the files and you don’t specify the @2x or .png file extension. There are two choices for how you name your launch images (splash screens):
Note for Universal apps: there are two other Info.plist keys that can be used – (Launch Image (iPhone)) UILaunchImageFile~iphone and (Launch Image (iPad)) UILaunchImageFile~ipad. These are useful because they allow you to use separate naming of iPhone and iPad launch images stored in the same app.
Note: iPhones do not support a landscape splash screen.
Physical screen sizes: 320 × 480 (640 × 960)
| iOS 3.1.3 Filename | Dimensions (Retina) |
Notes |
|---|---|---|
| Default(@2x).png | 320 × 480 (640 × 960) |
Default launch image. |
With iPads, the filename which is more specific will always be used first. For example, Default-LandscapeLeft.png will always be picked before Default-Landscape.png. So the files are listed below in the order that iOS will pick them.
Note also that with launch images that are for universal apps where you are using the same file names for both iPhone and iPad, you can add a device specific modifier (~iphone or ~ipad) to the end of the file name to separate them. For example, here is a launch image file name for a landscape Retina iPad for a universal app: MyLaunchImage-LandscapeLeft@2x~ipad.png
Physical screen sizes: 768 × 1024 (1536 × 2048)
| iOS 3.1.3 Filename | Dimensions | Notes |
|---|---|---|
| Default-PortraitUpsideDown(@2x).png | 768 × 1024 (1536 × 2048) |
|
| Default-Portrait(@2x).png | 768 × 1024 (1536 × 2048) |
|
| Default-LandscapeLeft(@2x).png | 1024 × 768 (2048 × 1536) |
|
| Default-LandscapeRight(@2x).png | 1024 × 768 (2048 × 1536) |
|
| Default-Landscape(@2x).png | 1024 × 768 (2048 × 1536) |
|
| Default(@2x).png | 768 × 1024 (1536 × 2048) |
Try to use more specific ones above. |
Finally you can also provide launch images for when you app is launched as a result of a custom URL schema. These launch images are the same as those above, however they also include the scheme as part of the file name. For example, if you app has registered as responding to the scheme myurlscheme:, then using the example above, the launch image would be called: MyLaunchImage-myurlschemeLandscapeLeft@2x~ipad.png
Posted on 30 July 2012, View commentsIt’s been some time since I’ve posted anything because I’ve been very busy. In the last while Ive been looking into some new project management methods. Two in particular – git submodules and XCode sub projects.
Prior to playing with this my methodology for wrapping up common code and building re-useable was to build an XCode project that generates a static iOS framework and use the scripts from dUsefulStuff . I wrote these scripts to perform several tasks:

Pros:
Cons:
Recently I’ve noticed a new trend which is quite different to the techniques I had been using above. It involves two separate technologies being employed:

Pros:
Cons:
Whilst trying various options and experimenting with all of this I came across a 3rd option which I haven’t seen anyone use yet: XCode workspaces. Workspaces are a new idea in XCode, basically you create a workspace and then add your projects to it. A single project can exist in multiple workspaces at the same time which means each project only has to exist once on your drive. All projects are displayed at the same level in a workspace and you can work on any of them.
Dependencies appears to be a simple matter of references the libraries built by framework projects in the same way as you would when referencing sub-projects. In other words, through the Link binaries with libraries build phase. When you select to add a binary in this way, XCode shows you all the binaries you workspace can build as options. But you don’t need to specify these projects as dependencies. XCode works out the build order automatically.
Pros:
Cons:
From looking at the above it would appear that there is no one single solution that works well for co-developing a group of projects. Every solution I have found so far has both pros and cons. I’m still in two minds about the best way for me to work. Especially as the git submodule, XCode sub-project system seems to be being adopted by developers, yet as far as I can tell, still has a number of issues.
Finally Luke from Cocoaheadsau reminded me of something I missed. If you are dealing with projects from other developers (sourced from GitHub for example), it’s a good idea to fork them first so that you can commit your changes and track them. You can fork locally or on github depending on what you want to do.
Posted on 25 July 2012, View commentsIn my dUsefulStuff static library project I have a define which defines a logging macro depending on whether a preprocessor debug flag is set. It looks something like this
#ifdef DC_DEBUG
#define DC_LOG(s, ...) \
NSLog(@"%s(%d) %@", __PRETTY_FUNCTION__, \
__LINE__, \
[NSString stringWithFormat:(s), ## __VA_ARGS__])
#else
// Effectively remove the logging.
#define DC_LOG(s, ...)
#endif
This makes things really simple when writing code because I can effectively include a pile of logging when developing and it all just disappears when I compile a release version. The output from NSLog is controlled by NSLog and looks like this:
2012-05-02 14:08:49.452 dUsefulStuff simulator unit tests[21353:f803] -[UIColor(dUsefulStuff) isEqualToColor:](15) My message!
As you can see it prints out these items of information:
2012-05-02 14:08:49.452dUsefulStuff simulator unit tests[21353:f803]-[UIColor(dUsefulStuff) isEqualToColor:](15)My message!The problem I have is that this takes up a lot of space and some of it I’m just not interested in. This has been bugging me for a while now and I’ve finally found a solution – swap out NSLog for CFShow like this:
#ifdef DC_DEBUG
#define DC_LOG(s, ...) \
{ \
NSDate *now = [NSDate date]; \
NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; \
[formatter setDateFormat:@"mm:ss.SSS"]; \
NSString *dateString = [formatter stringFromDate:now]; \
CFShow([NSString stringWithFormat:@"%@ %x %s(%d) " s, dateString, pthread_mach_thread_np(pthread_self()), __PRETTY_FUNCTION__, __LINE__, ## __VA_ARGS__]); \
[formatter release]; \
}
#else
// Effectively remove the logging.
#define DC_LOG(s, ...)
#endif
which prints out a line like this:
08:49.452 f803 -[UIColor(dUsefulStuff) isEqualToColor:](15) My message!
Here all I’m printing is the current minutes:seconds:milliseconds, thread-id, location and then my text. It may seem like this is not much different but it can make quite a difference when there looking through a log.
Posted on 02 May 2012, View comments
I’m pleased to release Simon build v0.1.8 The emphasis for this release is a re-worked UI. It’s been cleaned up and new functionality added. Now you can re-run all tests, some test or an individual test. This is particularly useful when debugging.
Posted on 08 April 2012, View commentsRunning XCode from a non-Admin user works reasonably well. However there are a few little quirks. One is that when you attempt to run your application in the Simulator, XCode will prompt for permission to modify system settings so that it can go into debug mode. This is rather annoying because it does this every time.
The root of the problem is that non-admin users are not in the “Developer Tools” security group. Even more annoying is that if you look in “users and groups” in settings, there is no such group present. The group exists, but it’s a unix group so you have to add the user at the command line. Googling around I found two commands that will do this for you:
# Option 1
sudo dscl . append /Groups/_developer GroupMembership <user>
# Option 2
dseditgroup -o edit -u <admin_user> -t user -a <user> _developer
Notice that the name of the group is _developer. I have not looked up these commands in detail to see exactly how they work, but they do the job. I went with option 2 which I found worked very well. It prompted me for the admins password and everything was fixed. I can now run my app without having to enter the admins userid and password every time.
Posted on 02 April 2012, View commentsIt’s been a while since I’ve announced a new version of Simon so I thought I’d drop a note to say that I’ve just uploaded the DMG file for version 0.1.7. This release contains a lot of new stuff and fixes, including the ability to enter text and wait for animations to finish. Enjoy!
Posted on 24 March 2012, View comments(Disclaimer – yes I work for Sensis :-)
Recently I was asked to do an upgrade a web site at work to replace an ageing search function with Sensis’s new SAPI search engine so I thought I’d put up a small discussion of how I went about it.
SAPI is a restful JSON based service which external developers can use to search both Yellow and White Pages listings combined. Providing a web based API allows developers to get creative and come up with new ways to utilise the information. In my case it was a fairly simple replacement of an established search with the SAPI search so it’s a good example of the basics of using this API.
To achieve this result I decided to make use of 3 core technologies apart from SAPI itself:
The first thing I had to do was to was to setup a HttpClient object ready to access the SAPI website and build a url to query the data. I’ll use some hard coded data here, but it’s easy to figure out where you would replace it with data from your input form. Note also that to be able to query the SAPI search engines you also need a SAPI Search API Key which is free for both development and production use.
// Get a client
DefaultHttpClient httpclient = new DefaultHttpClient();
// If you are behind a firewall and proxy you will probably need to enable this code.
// HttpHost proxy = new HttpHost("my.proxy.host.com.au", 8080);
// httpclient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
// Build the parameters we are going to add to the url.
// Note: There are many more than this you can use to refine this.
List<NameValuePair> parms = new ArrayList<NameValuePair>();
parms.add(new BasicNameValuePair("query", "Plumbers"));
parms.add(new BasicNameValuePair("rows", "20"));
parms.add(new BasicNameValuePair("page", "1"));
parms.add(new BasicNameValuePair("key", "xxxxxxxxxxxxxxxxxxxxx")); // This is your API key.
parms.add(new BasicNameValuePair("location", "Richmond"));
parms.add(new BasicNameValuePair("state", "VIC"));
// Use the developer connection URL.
URI uri = URIUtils.createURI("http", "api.sensis.com.au", "-1", "/ob-20110511/test/search", URLEncodedUtils.format(parms, "UTF-8"), null);
It’s pretty much what you are looking for, where and paging controls. SAPI has a lot of options you can add to refine your queries even further. For example, you can specify to include listings within a radius around a central location, or filter out potentially unsafe links for minors. Now lets execute the query and map the results into some java beans:
try {
// Send the search Request to SAPI.
HttpUriRequest request = new HttpGet(uri);
HttpResponse response = httpclient.execute(request);
// Get the Jackson object mapper which can read the results.
ObjectMapper objMapper = new ObjectMapper();
// Tell the object mapper to ignore JSON values we do not have a bean property for.
// Otherwise it will throw an exception.
objMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// Tell the object mapper to use Mr Bean to create the bean classes.
objMapper.registerModule(new MrBeanModule());
// Unmarshal the JSON response into beans.
SapiSearchResult sapiResult = objMapper.readValue(response.getEntity().getContent(), SapiSearchResult.class);
} finally {
httpclient.getConnectionManager().shutdown();
}
So that’s the SAPI, Httpclient and Jackson parts done and we now have java beans all ready for using in our UI. But wait … Where did those beans come from?
The reason I have not started by defining beans is because Mr Bean makes it so easy as to be trivial. Prior to this you would have had to define your java beans as fully realised classes. For example, here’s a simple version of SapiSearchResult (there are a lot more properties you can add! ):
public class SapiSearchResult {
private int totalResults;
private int code;
private String message;
private List<SapiListing> results;
int getTotalResults() {
return totalResults;
}
void setTotalResults(int totalResults) {
this.totalResults = totalResults;
}
int getCode() {
return code;
}
void setCode(int code) {
this.code = code;
}
String getMessage() {
return message;
}
void setMessage(String message) {
this.message = message;
}
List<SapiListing> getResults() {
return results;
}
void setResults(List<SapiListing> results) {
this.results = results;
}
}
Phew! image what you would have to write for the full API if your JSON processing API (unlike Jackson) cannot handle un-mapped properties and you have to boiler plate everything – SAPI can return a lot of data! Luckily I’m using Jackson so I can use two different tricks to avoid all this work:
With Mr Bean we can simply define a Java interface for the properties we want from the JSON response and let Mr Bean dynamically create the Java implementation of the bean class on the fly. So SapiSearchResult now becomes:
public interface SapiSearchResult {
int getTotalResults();
int getCode();
String getMessage();
List<SapiListing> getResults();
}
That is a huge difference. Mr Bean will handle creating the setters, constructors and implementations. It handles arrays, maps, lists, Enums, and everything else. The only thing it needs is the getter definition to tell it what to create. You can even add custom code simply by defining an abstract class instead of an interface and adding in the custom methods you want. Wicked.
I would have to say that between the ease of use of the SAPI search engine, HttpClient and the Jackson/Mr Bean combination, it has taken a surprisingly small amount of time to get a working result. Even when factoring in other stuff such as exception handling and UI.
I would also have to say that the SAPI web site is excellant. As a developer, it’s exactly what I want to see when it comes to documentation and support. The site also contains plenty of examples of using their API in Java, PHP and Ruby. Well done guys.
Posted on 08 March 2012, View commentsOver some time I’ve come to realise that the difference between a good piece of software and a crap one has nothing to do with methodologies, practices, patterns, principles or any of the other things so many people like to bandy about. It simply comes down to one thing that has not changed since we first start writing code – The best software comes from those who use it themselves.
When you design an application you making a best guess at what is needed, but when you use an application you know what is needed. This doesn’t sound like much, but it makes a massive difference. I often find that when I first visualise a piece of software I can come up with all sorts of UIs, features etc as part of working out what I want to do. Some of those I drop and some I code up in the application. But it’s only when I take the developer hat off and try to use the software that I find out that my groovy button is in fact, not that groovy. Or that the input fields that made sense when thinking about a particular function makes no sense when I actually want to do it. So I I tend to write a piece of software as a V1, or more to the point, a v0.1, and then usually find myself making some quite significant changes in V0.2 or even v0.3. After each stage I to take the software out for a run and try it in the real world, expanding my understanding of the problem space. Something the application doesn’t work as well as I hoped and go back in to re-engineer in light of the new experience I now have. At some point the software goes from being a potential solution to being something that I can actually use.
I think one reason why 90% of the enterprise software I have been around basically sucks is that this does not happen. There are thousands of enterprise developers out there, spending huge amounts of time writing applications to specifications drawn up by Business Analysts and Enterprise Architects, none of whom are ever going to actually use that software. And frankly some don’t even know what it does! So the result is a pipeline of people’s best guesses based on other peoples best guesses of what the actual need is, usually defined by someone else who is also not going to use the software. It’s even worse when dealing with software which just talks to other software. And of course, the developers usually only get one shot at writing the software which means there is no real chance for building an understanding through experience. So it it really that surprising that the results are pretty poor and often over-engineered?
But isn’t Agile, Patterns, Practices and Principles going to fix this. Or at least that’s what the evangelists would have us think. After all, all we have to do is following these things religiously and we will be writing better software. Hang around in the Java enterprise world long enough and you will come across everything from hard bitten practicality to zealous idealised evangelism. This is where I think we have to split the myth from the reality. Talking to some people it all sounds very reasonable – all you have to do is follow <insert acronym here> and you will be creating amazing software is no time … Simply not true.
Writing good software that actually helps rather than hinders has nothing to do with these things, it comes down to a clear vision of what has to be done coming from a clear understanding of the need it has to fulfil. You cannot get this from a one shot project and you will definitely not get it from writing software you will not use. Sure, experienced developers have the experience and skills to know the questions to ask and can better separate the practical needs from the dreams and distractions. So experience counts in getting closer to a worthwhile application – faster, but it’s still no substitute for going through successive iterations of writing code and using it.
But what about all the APPP? (Yes I had to throw in an acronym, you figure it out) Those things are very worthwhile and I’m not dissing them. They sum up years of hard won experience, distilled down into something we can all use by some very smart people. Learning them and understanding where they can be used will help you to write cleaner, simpler, easier to understand code.
But they are not a magic pill, or silver bullet or whatever you want to call it and you cannot automatically write great applications just by religiously following them. What they really are is a great set of tools to help you get the job done better, in the same way that a workshop full of the best quality tools can help a craftsman make a great chair. Usually with less effort and time than if all you gave him was an axe. Either way you will still get a chair that you can safely sit on and will probably treasure. Send in someone who knows nothing about chairs and doesn’t like sitting down and all you will get is a pile of fire wood, regardless of the tools. Send in an Agile evangelist and you will get a joinery demonstration, book and TV show. The chair will be extra. You get what you pay for after all.
Finally remember this, great software was being written long before we had TDD, FDD, LSP, Facades, OCP, BDD, DRY, CI servers, YAGNI, KISS, Interfaces, Unit Testing, SRP, Decorators, ISP, DIP, etc etc. So just because someone does not know these things, or has chosen not to use them in a project, doesn’t mean they don’t know how to write great code.
Posted on 06 March 2012, View commentsI’ve now released Simon V0.1.3 which is a large update. New and included things are:
Simon is now (I’m rapt to say) at the point where it feels like a usable product. So I’m now planning to use it as part of updating Crema, which I’ve left a bit by the way side whilst doing other things. This will help me firm up what Simon needs next. Although I already have some ideas for new macros and enhancements to the core and UI reporting functions.
Posted on 03 March 2012, View comments