Thursday 17 December 2009

iPhone: Forcing a UIView to reorientate

In my current iPhone application I need to force a UIView to reorientate when a certain event happens. The SDK doesn't really allow for this to happen.

There's the well-known UIViewController method
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation that is called whenever the user rotates the iPhone. If you say YES to that orientation then the OS does the spade work of rotating the display and your views for you. However, you cannot manually ask to rotate the screen, so if you decide that your shouldAutorotateToInterfaceOrientation: peccadillo has changed, there's no way to tell the OS.

The blind alley

There are a number of blog posts, discussions, and Stack Overflow posts that suggest you use the private setOrientation: method of the UIDevice class. This is all well and good apart from two issues:
  1. It's a private API. You won't get into the App store if you use it.
  2. More importantly, it doesn't work.
This seems the canonical version of that method:
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeLeft];
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeLeft];
It serves to rotate the status bar, but leaves your UIView where it is.

How to make it work

Until Apple bless us with an official API for doing this, here's how I managed to achieve my goal...

Once I have decided that I want to orientate a different way, and arrange to return a different shouldAutorotate answer, you must change your window's subview hierarchy. Doing this forces the OS to ask you about your rotation support and wiggle everything around appropriately.

Based on the fact my app has a parent UINavigationViewController at the top, which puts a single subview into the UIWindow, this is what I do:
UIWindow *window = [[UIApplication sharedApplication] keyWindow];
UIView *view = [window.subviews objectAtIndex:0];
[view removeFromSuperview];
[window addSubview:view];
It's a bit unpleasant, but it works. I tried variants such as removing the window and then making it the keyWindow again, however that didn't trick the OS into asking for rotation state again.

I hope this helps you. As ever, if you know a better way of doing this, please let me know!

Tuesday 15 December 2009

The git equivalent of svnversion

I've been happily using git as my version control weapon of choice for some time now. It's integrated into my automatic build, test, and release scripts neatly. The world is a nice place.

Except, I've not really found a compelling replacement for Subversion's svnversion. I used to use svnversion in my release scripts to name the final build disk image nicely, something like "fooproject-SVNVERSION.dmg", as well as versioning some of the files inside the image.
What is svnversion?
svnversion is a cute little command line tool that looks in the current working directory to determine which revision of a subversion repository you have checked out. If your head revision is 215, and you have all files checked out at HEAD, then running svnverison you'll get:
pete@solomon > svnversion
215
If you have some older files, then you'd get something like:
pete@solomon > svnversion
200-215
And, if your working copy contains some files with uncommited local changed, then you'd get a helpful M added to the end:
pete@solomon > svnversion
200-215M
It is possible to get something similar to svnversion using git's git describe command. In some ways it is superior to Subversion's simple monotonically incrementing numbers, in some ways inferior. By necessity, it works differently from svnversion.

git describe looks at the git revision you have checked out, and produces the name of the nearest tag followed by the number of commits since that tag, and a partial SHA-1 value of the current commit. This is relatively cute:
pete@solomon > git describe
v0.7-8-gf20bae60
However, there are issues:
  • Firstly, it doesn't mark whether there are local uncommitted modifications in your local tree.
  • And the partial SHA-1 at the end may not always be valid. If your project gets large enough that more characters are required to unambiguously identify one SHA-1 value all older "git describe"s will no longer uniquely identify a revision.
We can't fix the latter issue, but we can tweak a little to add some "M" love to our git description.

Try this little bit of bash scriptery:
git_version()
{
GITVERSION=`git describe`
GITMODIFIED=`(git st | grep "modified:\|added:\|deleted:" -q) && echo "-M"`
echo $GITVERSION$GITMODIFIED
}

That's a little more useful.

If you know a better way of doing this, I'd love to know!

Friday 11 December 2009

Speaking: ACCU 2010

The ACCU 2010 conference schedule has been ceremoniously unvieled on the ACCU website, here. It looks as strong as ever.

This year I will be presenting two whole sessions for your delight and delectation.
  • The first, poetically entitled Stood at the Bottom of the Mountain Looking Up, is an investigation into how to quickly get up to speed with new technologies, languages, problems, etc. It'll be an interesting and practical "soft skills" kinda thing. I'm not sure how to weave inappropriate imagery into the talk yet, but I have plenty of time to work on it.
  • The second, snappily entitled iPhone development is a talk about, well, iPhone development. It's a co-presented session with the esteemed Mr Phil Nash. Goodness knows how we'll cover the ground in a mere 90 minutes! I'm really looking forward to this one.
I should probably do something about the biography that's currently up there. "Pete owns some shoes. But won't wear them." is accurate but perhaps not too descriptive.

Thursday 10 December 2009

Boost on the iPhone

This is the simple way to get Boost into your iPhone code.

I've been porting a large C++ project to the iPhone. It uses the excellent Boost libraries. Building Boost for the iPhone is not impossible, just a bit of a pain in the arse.

There are a number of good examples of how to do this online, for example the Backstage blog entry here and Matt Galloway's blog here. They are useful hints that help you work past the impenetrable Boost Build documentation.

However, the story does not end here. Those instructions allow you to build a set of libraries for the simulator, or for the iPhone OS. But not both. This means that your Xcode project setup gets fiddly with different link paths for the different targets.

You can solve this by creating a "universal" fat library. The lipo tool can be used to shunt the individual libraries together. Not tricky, just another step.

Now, for bonus points it would be sweet to construct a "Framework" for the Boost libraries, allowing you to use them in Xcode like any other iPhone framework. I've already blogged on how to do this here.

Of course, if you were sensible, you'd wrap this up in a script so that anyone can use it. A script a bit like this one.

I've set up a Gitorious project for this script. Feel free to use it.