Simplifying Ad-Hoc Distribution

As an iOS freelancer, I work with many different clients every day, who all have their own processes and workflows. Distributing ad-hoc builds is just a small part of developing an app, but it’s usually the first experience a client will have with your work, so it’s important to make this process as smooth as possible.

There are many different ways of distributing builds. TestFlight and HockeyApp are two well known services, while Over the Air (OTA) is more of a manual style of distribution. Each have their own advantages and disadvantages, but the main thing I’ve noticed is that every client has different needs and different preferences – there’s no one size fits all option.

With this in mind, I’ve been developing a tool to make the process of distribution more uniform, so that regardless of what service or method you might use, the interface remains consistent. It’s very much a work in progress, but here’s how it looks today:

Work in Progress

After selecting a IPA file, you have the option to select your destination. Currently the app supports Dropbox, FTP, and SFTP, but I’ll be adding TestFlight, HockeyApp and Amazon S3 in the near future. The Directory might be the name of your client, while the Files section lets you select which files to upload. Finally, there’s a section for release notes. Tapping Go will create the relevant Property List and HTML files necessary for OTA distribution, and then upload all the files to your chosen destination.

The nice thing about controlling this process via code is that we can include some handy information on the HTML installation page, or in the case of TestFlight or HockeyApp, this information gets passed on directly:

HTML output

It’s usable currently, but there’s still a lot of work to do, some of which includes:

  • more destinations, eg. TestFlight, HockeyApp, Amazon S3
  • ability to upload different files to different destinations. For example, you might store the Property List in Dropbox, and your HTML file on an FTP server
  • ability to upload dSYMs
  • ability to upload other related files (eg. logos etc)
  • ability to customise the output HTML
  • proper user preferences and account setup
  • options for post-upload tasks, eg. shorten URL for the HTML file, send an email, etc
  • ability to save and load different arrangements for different clients

I also need to spend a lot more time on the interface. Being my first OS X app, I’ve found the UI to be quite a challenge – even just knowing which controls to use can be difficult.

With Apple’s recent acquisition of TestFlight’s parent company, the future for this tool is a little unclear at this point. The main thing is that I’m finding it useful today. If it sounds like it might be interesting to you as well, let me know, I’d love to hear your feedback.

Pretty Pie Charts with XYPieChart

XYPieChart is a simple to use, great looking component for drawing pie charts in iOS apps. I recently needed a pie chart for an app I’m working on, and I can honestly say this was one of the nicest experiences I’ve ever had with a 3rd party component. This video on Vimeo gives you a nice overview of it’s capabilities.

XYPieChart

Out of the box, XYPieChart looks fantastic, with a nice selection of colours and some snazzy animations. Of course, this is all customisable – select whatever colours you like, turn animations on or off, change the fonts – most of these customisations are just a single line of code. In fact, I only have a total of 16 lines of code in my UIViewController for displaying, customising and updating my pie chart.

XYPieChart uses the datasource and delegate pattern, which should be familiar, and the clean and simple API is pretty much self explanatory. For example:

- (NSUInteger)numberOfSlicesInPieChart:(XYPieChart *)pieChart {
    return self.values.count;
}

- (CGFloat)pieChart:(XYPieChart *)pieChart valueForSliceAtIndex:(NSUInteger)index {
	NSNumber* value = self.values[index];
	return value.doubleValue;
}

Couldn’t be easier, right?

If you ever have a need for any sort of pie chart in your iOS apps, I would definitely recommend giving XYPieChart a go.

Are you using Parse yet?

As an iOS developer who finds creating databases and web services incredibly boring, Parse has always sounded very attractive. For those who don’t know, Parse provides a way for developers to store data in the cloud. They offer a number of other services as well, such as push notifications, cloud-based code, and social integration, but I believe data storage has always been their core business. There’s no databases to setup, no web services to create, no servers to maintain – all you need to do is focus on creating a great front-end product, and they do the rest. At least, that’s what I was expecting without ever having used it before.

I finally had a chance to play with Parse this week, and I was very pleased to find out that Parse lived up to my expectations, and more. It’s incredibly simple to setup and develop for, and I’m now falling over myself to try and find more projects to use with it. Here’s a few of the things that really impressed me.

Simplicity
Storing and retrieving data is drop-dead simple. Here’s an example from their documentation:

PFObject *gameScore = [PFObject objectWithClassName:@"GameScore"];
[gameScore setObject:[NSNumber numberWithInt:1337] forKey:@"score"];
[gameScore setObject:@"Sean Plott" forKey:@"playerName"];
[gameScore setObject:[NSNumber numberWithBool:NO] forKey:@"cheatMode"];
[gameScore saveInBackground];

And…we’re done, the object is now stored on Parse’s servers. No tables had to be created, no columns had to be defined. There’s several ways you can save data too, including block-based completion callbacks, and even the ability to automatically save later in case the network connection is down.

Retrieving data is just as easy:

PFQuery *query = [PFQuery queryWithClassName:@"GameScore"];
[query getObjectInBackgroundWithId:@"xWMyZ4YEGZ" block:^(PFObject *gameScore, NSError *error) {
    // Do something with the returned PFObject in the gameScore variable.
    NSLog(@"%@", gameScore);        
}];

Documentation
This has to be one of the biggest reasons why I’ve fallen in love with Parse. The documentation is first-class. Plenty of code samples, plenty of sample projects, clear and concise explanations. It doesn’t get any better than this.

Data Browser
If you want to take a look at what data you have online, Parse provides a Data Browser. This works somewhat like a spreadsheet. You can view all your data, update and edit as you need, and it all just works. Your data is very much open and visible to you, which makes debugging much simpler. I think it could also be great as a lightweight CMS.

So why shouldn’t you use Parse? There’s a few reasons I can think of:

  • You don’t own the data. If Parse disappears one day, it’s going to cause problems.
  • It doesn’t replace a full CMS, so might not always be suitable
  • Parse was recently acquired by Facebook, so I guess it remains to be seen exactly what the future holds

For me, the positives far outweigh the negatives. If you’ve never tried Parse, it’s well worth the effort to spend an hour taking a look. My only regret is that I didn’t look into it sooner.

Photo Academy for iPad – Now Available

I’m very pleased to announce that after more than a year of development, the iPad edition of Photo Academy is now available.

For those who are new to Photo Academy, the aim of the app is to help anyone who owns a camera to take better photos.

Photo Academy for iPad contains thousands of detailed tips on how to take the best photo in almost every situation, including the exact camera settings to use. Beginners can get up to speed quickly by following a broad range of tutorials, which cover all the different aspects of photography. The app also allows you to show off your skills in the Shoot Diary, by tracking photo shoots, sharing them with friends, and seeing where in the world you’ve taken your best photos.

For more information, please take a look at the Photo Academy for iPad website, or simply search for Photo Academy on the App Store. Alternatively, if you have any feedback or suggestions, I’d love to hear them!

Photo Academy for iPad screenshot

Photo Academy for iPad screenshot

Photo Academy for iPad screenshot

Photo Academy for iPad screenshot

Photo Academy for iPad screenshot

Scheduling Your Work Day

Ever since becoming someone who works from home, one of the things I’ve struggled with is keeping my focus on what I’m doing, and not being distracted by incoming work. I often find myself checking my email, receiving an email from a client who needs something fixed, checked, or investigated, and immediately dropping what I was currently working on to take care of this new demand. There’s certainly something to be said for clearing the decks and getting things out of the way as quick as possible, but it can also be very disruptive, and worse, inefficient.

I recently came across a podcast aimed at people who work from home, aptly named Home Work. I’ve really been enjoying going back over all the old episodes, and there’s some great discussion in there on all aspects of working from home. If you’re a home worker, I really recommend giving it a try, starting at the first episode.

One of the best tips I’ve picked up from Home Work so far is to consciously schedule your work day. The idea is to not only plan out what things you are going to work on that day, but also to put times against them. I’ve been giving this a try for the past few days, and by way of example, this is what my schedule looks like for today:

  • 9am – 10am: write blog post
  • 10am – 12.30pm: work on promotional material for an app I’m launching soon
  • 12.30pm – 1pm: lunch
  • 1pm – 3pm: work on bug fixes for a client app
  • 3pm – 5pm: continue developing my new app idea

Once 5pm rolls around, I’ll take a look over all my current projects, decide what I’m going to work on tomorrow, and write up a schedule for myself for the next day. This only takes a few minutes, but so far it’s working out wonderfully. I don’t waste time in the morning trying to figure out my plans for that day, and I feel much more relaxed in the evening after finishing work, knowing that everything is on track, and anything that needs to be progressed has been scheduled in. I think the biggest benefit is that one particular project cannot take priority over another. So if I haven’t finished writing my blog post by 10am, I need to shelve it for the next day – 10am is the time to move on to the next project. This way everything moves along, rather than getting left behind.

At some point I think I’ll start scheduling in half an hour or so each day to take care of “stuff”, such as unexpected phone calls, emails, and so on, but so far I haven’t needed it.

And with that, it’s 10am, and time to move on to my next project. If this idea appeals to you, give it a try for a week – it’s made a big difference in my happiness and productivity.

Rotating a Paged UIScrollView

Adding rotation to your app is one of those things that users often expect, but which can really bump up the complexity of development. In most cases autosizing your content works nicely, but it’s not unusual to run into things that just don’t behave quite as you might expect.

I came across one of these recently with a paged UIScrollView. The content was a number of full-screen photos, which allows the user to swipe left and right to change photos. This is a fairly common use of a UIScrollView, and has a nice bang-for-your-buck feeling about it – it’s pretty easy to setup, and results in one of the most natural way to view your photos.

That is, until you enable rotation. The first problem that you’ll likely encounter is that all your pages suddenly overlap each other (or have big spaces between them). This is easily fixed by updating the origin of each page to reflect the new dimensions of the UIScrollView.

The next problem you’ll come across is that the UIScrollView content offset is still in the same position as it was prior to rotation. This usually results in your UIScrollView being stuck between two photos, with only a portion of each photo being visible. If you’re really unlucky, your content offset will be past the new width of the UIScrollView, so that you can’t see anything at all. Either way, as soon as you try to move the content, it will jerk back into the right position for one of the pages (though, not necessarily the right page).

The easiest solution to this is to simply update the content offset once rotation has completed. As long as you know which photo you were viewing before, and what the width of the UIScrollView is, this is easy to do with some simple maths. However, this approach is not as polished as it could be. You still get all the problems mentioned previously, and the only difference is that the UIScrollView jerks into position automatically, rather than when you try and interact with it.

We can do better. The next approach would be to animate changing the content offset. UIViewController exposes a very handy method that lets you know when the rotation is about to occur:

willAnimateRotationToInterfaceOrientation:duration:

So, we simply make a call to change the content offset inside this method:

[self.scrollView setContentOffset:CGPointMake(X,Y) animated:YES];

However, this doesn’t quite work as expected either. As the rotation animation occurs, you can see the edges of the other photos move in and out. You start and end in the right position, but you shouldn’t see any parts of the other photos as the rotation is going on. I’m not entirely sure why this is – possibly because the content offset animation is handled using the animated: parameter, rather than in a block based animation with the same duration as the rotation. A handy trick when using the iOS Simulator is to tap the Shift key three times. This turns on slow motion animations, and make it’s much easier to see what’s really going on.

The next approach might be to manually update the content offset one pixel at a time, in sync with the rotation animation. This sounds like a nasty hack though, and there’s a better way – it just requires a little thinking outside the box.

The trick is to actually remove the current page from the UIScrollView before rotation, add it to the parent UIView, and hide the UIScrollView. Then, once the rotation has completed, update the UIScrollView content offset (not animated), put the page back into the UIScrollView, update all the frames of the UIScrollView to reflect their new positions, and then unhide the UIScrollView. Something like this:

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
self.scrollView.hidden = YES;

//remove the current PageViewController and place it in the parent view
PageViewController* pageViewController = [self.pageViewControllers objectAtIndex:self.currentPageIndex];
CGRect frame = pageViewController.view.frame;
frame.origin = CGPointZero;
frame.size = kScrollViewLandscapeSize;
if(UIInterfaceOrientationIsLandscape(toInterfaceOrientation)) {
frame.size = kScrollViewPortraitSize;
}
pageViewController.view.frame = frame;
[self.view addSubview:pageViewController.view];

//animate the frame change for the pageViewController
[UIView animateWithDuration:duration animations:^{
CGRect frame = pageViewController.view.frame;
if(UIInterfaceOrientationIsLandscape(toInterfaceOrientation) {
frame.size = kScrollViewLandscapeSize;
}
else {
frame.size = kScrollViewPortraitSize;
}
pageViewController.view.frame = frame;
}

completion:^(BOOL finished) {

CGSize scrollViewSize = [self scrollViewSizeForCurrentOrientation];
[self.scrollView setContentSize:CGSizeMake(scrollViewSize.width*self.tips.count, scrollViewSize.height)];
[self.scrollView setContentOffset:CGPointMake(scrollViewSize.width*self.currentPageIndex, 0)];

//put the pageViewController back in the UIScrollView, and update the frames for all the PageViewControllers inside the UIScrollView
[self.scrollView addSubview:pageViewController.view];

[self.pageViewControllers enumerateObjectsUsingBlock:^(PageViewController* pageViewController, NSUInteger idx, BOOL *stop) {
CGRect frame = pageViewController.view.frame;
frame.origin.x = scrollViewSize.width * idx;
pageViewController.view.frame = frame;
}];
self.scrollView.hidden = NO;
}];
}
}

A neat little trick that has the desired effect – smoothly animated rotations that behave just as you’d expect!

MyMoodTracker for iPad – Now Available

I’m pleased to announce that after many months of hard work, the iPad edition of MyMoodTracker is now available. The app feels great on the larger screen, and should allow for some interesting and useful insights into one’s mental health.

For those who are new to MyMoodTracker, it’s focus is on keeping track of how you are feeling throughout the day, and determining what factors have an influence on your mental state. Did I get enough sleep last night? Did I drink too many soft drinks yesterday? Am I on track with my medication? The things that affect your mood are many and varied, and MyMoodTracker helps you identify those patterns and get on the path to feeling good.

If you’re a regular user of the iPhone edition of MyMoodTracker, you’ll be pleased to know that data can easily be synced between the two. Make your entries on your iPhone when you’re out and about, and analyse them later on the big screen of the iPad. There’s also some interesting additions to the iPad version, such as the handy statistics summary.

For more information, please take a look at the MyMoodTracker website, or simply search for MyMoodTracker on the App Store. Alternatively, if you have any feedback or suggestions, I’d love to hear them!

MyMoodTracker for iPad Screenshot 1MyMoodTracker for iPad Screenshot 1MyMoodTracker for iPad Screenshot 3MyMoodTracker for iPad Screenshot 4MyMoodTracker for iPad Screenshot 5

 

Developing with a Magic Trackpad

As I don’t own a laptop, I’ve always felt that by using a mouse that I was missing out on some of the nice touch features of OS X. The Magic Trackpad is the obvious solution, but I was never able to get over  that sceptical feeling of how well it would work as a mouse replacement. Since I have several Magic Mouses (Magic Mice?) lying around already, when I bought a new iMac recently I decided to get the trackpad instead. I commited to trail it for two weeks, and if I was still finding it difficult at the end of that period, I’d go back to the trusty mouse. Those two weeks are now up, so here’s my verdict.

The first thing I noticed is that the transition was really quite natural. I have used Apple laptops before so it’s not like I’ve never used a trackpad, but I think all those years of performing gestures on iOS devices just made me feel instantly at home with the trackpad. I was fully expecting to spend at least a few days feeling hindered, but the truth is I was up and running at normal speed almost instantly. All I needed was a little messing around in System Preferences to get the cursor speed correct. The gesture demonstrations in the System Prefs are excellent, and really make it clear what gestures are available.

If you’re not too picky, then that’s really it. Developing in Xcode is great, navigating the OS is fun, and everything just works. Even doing the occasional touchups or cuts in Photoshop works just fine, though I’m not sure how well it would be for someone who spends all day designing pretty things.

If you are picky like me, then there’s two things which may bug you. The first is creating IBOutlet connections in Xcode. I love the ability to drag connections that was first introduced in Xcode 4, and would always do this by right-click and dragging. However, I can’t find a way to make this work with the Magic Trackpad. The only way I’ve found to make connections so far is to hold down the Control key, and perform a 3 finger drag. A little cumbersome, but not that big of a deal.

The other issue I came across is not so much of an issue as it is more of a side effect. When dragging things around with a trackpad, you will inevitably sometimes reach the edge of the trackpad before you’ve fully dragged the item to it’s destination. Imagine dragging a file from one side of the screen to another – chances are you reach the edge of the trackpad first unless you’re quick. To combat this, the trackpad gives you a little bit of time to readjust. For example, you can drag a file halfway across the screen, lift your fingers off the trackpad and move them back to the other side, and continue dragging. As long as you’re quick enough, this works great. The problem comes in when testing apps in the iOS Simulator. Often you’ll need to swipe or scroll, and because of the way the drag detection works, once you finish your swipe/scroll the screen sticks there for say a tenth of a second – just long enough for the OS to decide that you’re not trying to continue the gesture. Imagine scrolling a UITableView, and see it stick for just a little bit of a time after you finish scrolling. This really isn’t a big deal, as long as you test on a device and confirm that this stickiness is not just bad code!

So, all in all, I love the Magic Trackpad, and I’m sticking with it. If you decide to give one a try, spend a few minutes familiarising yourself with all the gestures that aren’t possible with the Magic Mouse. There’s quite a few. You also might want to consider installing BetterTouchTool. It gives you a high level of customisation over how your trackpad behaves. Currently I’m only using it to alter Safari’s behaviour when tapping on links – basically if I perform a 3 finger tap, it opens links in the background.


Enjoyed this post? Subscribe via RSS or follow me on Twitter.

Quit Checking Your Email!

Being a freelancer, I’m always on the lookout for things which can help to improve my workflow. One source of productivity tips is the Back To Work podcast with Merlin Mann. For those who don’t know him, Merlin is what I’d call a productivity celebrity. He created 43 Folders, and invented Inbox Zero. You’d think that after 73 episodes of Back To Work, there wouldn’t be much more to talk about. Unfortunately, I’d probably agree! Each episode generally runs for about 90 minutes, and these days only seems to contain 5-10 minutes of what I’d call useful material. So, instead of recommending you go and subscribe, I’m going to detail a few of the things I learned from B2W that have made a big impact on my productivity – and they’re all to do with email.

The first tip is to realise that it’s very unlikely that you work in a job where you need to respond to an email as soon as it arrives. How often are you in a situation where your livelihood depends on you replying to that email instantly? Not very often I’d say. So how long can you leave it? 5 minutes? 30 minutes? 2 hours? Chances are if the sender does require an urgent response, they’re just going to call you up anyway.

Once you’ve realised that checking your email is not all that important, the next thing to do is turn off that badge. You know, that little red badge in your dock which says how many unread emails you have. If you’re anything like me, once you see a red badge you need to care take of it straight away. It’s sits there whispering to you – “hey, unread email over here…hello, pay attention to me”. Not good! Head on in to preferences and get rid of it, and I promise a few days later you won’t miss it at all. Same goes for your iPhone as well – don’t let your email be pushed to your device, set it to manual fetch only.

The next step is to actually quit your email client altogether. I’ve gotten into a bad habit recently of checking my email whenever I’m waiting for something (eg. a build to complete). Naturally there’s one or two emails there waiting to be read, so I read them, and my attention gets pulled away to something else. Instead, try quitting your email client. Then, once you’ve finished a chunk of work, open it back up and take care of your emails all at once. Or if you have enough self control, just stare out the window while you’re waiting for that build to complete. Hands off the mouse!

Depending on how much email you get, you might like to think about Inbox Zero. There’s a few different ways to approach Inbox Zero, but what I like to do is treat my inbox as a bit like a to-do list for the day. If there’s any emails in my inbox, they’re either unread, or they’re emails that I need to care of that day. Once I’ve processed an email (replied to it, stored the attachment, whatever needs to be done), the email gets archived. So at the end of each day, my inbox is empty. The easiest way to get started with Inbox Zero is just to move all your emails to an archive folder – hey presto, Inbox Zero! You can go back and sort those thousands of emails later if you want, but don’t let that task prevent you from starting.

Inbox Zero also works really well with flags. Flags are great for when you want to clear out your inbox, but there’s certain emails you just don’t have time to take care of right now. For example, any personal emails that I might want to look over on the weekend, I flag with a green flag. Any work related emails that I need to follow up on within the next few days I flag with a yellow flag. Any support requests I flag as blue. These emails can then be archived, and I’ll take care of them in a day or two – this is easy to do using a flags smart folder in your email client. So, when I’m dedicating some time to support, I can quickly call up all the emails with a blue flag and get through them.

The last tip I have is to use a different email client for your personal mail. All too often I want to read my email on the weekend, but I get bombarded with work emails – not good for work/personal life balance. This happens in reverse too – when there’s no boss looking over your shoulder it’s all too easy to open up that funny video your friend just sent you. So, find another email client, and use one for personal email, and one for work.

I hope some of these tips were helpful. Email can be a big drain on your productivity, but only if you let it. If you have any others tips, I’d love to hear them!


Enjoyed this post? Think we’re clever? Subscribe via RSS or follow us on Twitter.

An Interview with Beginning iOS Dev

I was recently asked by Beginning iOS Development if I would like to take part in an interview, which sounded like fun to me. We discussed a range of things, including marketing, designs, my background, and development life in general. I’m really happy with how it all turned out, so if this sounds like it might be of interest, wander on over and have a read: http://www.beginningiosdev.com/interviews/interview-with-ben-williams-of-aspyre-apps


Enjoyed this post? Think we’re clever? Subscribe via RSS or follow us on Twitter.