Tips for iPhone with a broken lock button

My iPhone 4 has a broken lock button. This is really annoying, because I can’t just press a button to lock the phone. I found a workaround, which makes it possible (though still clumsy) to lock the phone.

Settings | General | Accessibility | Physical & Motor | AssistiveTouch | On

This adds a small circle area that you can tap on and then it brings up a little popup in which you hit “Device” and then “Lock Screen”. This is still clumsy because it requires multiple taps and also because that little circle is constantly in my way – you can drag it around, but there’s no area of the screen where it’s not annoying some of the time. I have “Triple-click Home” set to AssistiveTouch so I can do a triple click to toggle the dot, but it’s hard to get the device to recognize the triple tap and it tends to be very laggy. Honestly, it’s almost worse than having the dot there all the time.

Another problem that I only recently solved a few days ago is how to take a screenshot on a lock-button-challenged device. On a normal device, you hold down the home button and hit the lock button to take a screenshot. This doesn’t work when your lock button doesn’t work of course. But it turns out that the virtual lock button in AssistiveTouch will emulate a lock button for the purpose of taking a screenshot as well! So to take a screenshot:

  1. Tap the AssistiveTouch dot.
  2. Tap “Device”.
  3. Hold down the Home button while tapping “Lock Screen”.

Voilà.

There is some more info about the AssistiveTouch feature (including a video) at the Assistive Technology Blog.

Find my iPhone weirdness and how I fixed it

A few weeks ago, my wife lost her iPhone 4 and we bought another one. When I set up the phone in iTunes, I did a restore of the backup of her old phone and everything worked great. Except that I could not get her phone to show up in Find my iPhone. I tried numerous times to delete and add the MobileMe account and I could not get the phone to show up. Not in me.com; not in the Find my iPhone app on my iPhone; not even in the Find my iPhone app on her own phone!

There was another weird symptom. When I tried to switch off Find my iPhone it instantly switched back on. This is kind of hard to explain, so here’s a video that shows the problem.

Deleting the MobileMe account and adding it back did not fix it. FMiP still switched itself back on.
Restoring to a previous backup did not fix it.
Restoring as new worked but it nuked all of my wife’s data, so I would then have to do a lot of manual restoring.

My fix:

  1. Restore iPhone to latest backup with all of the data. All data now there, but FMiP switches itself back on again. (Tried deleting and recreating MobileMe account. No dice.)
  2. Go to me.com and remove the iPhone.
  3. On the iPhone, delete the MobileMe account
  4. Add the MobileMe account back again, but set Find my iPhone to off initially.
  5. Go back into the MobileMe account and turn FMiP on. Answer yes to two prompts – one that syncing will be disabled and one that location will be tracked.
  6. Refresh me.com, iPhone shows up! On the iPhone, I can now turn FMiP on and off at will!

Yay!

The quest for a better UIAlertView

One of the things that has annoyed me while developing my iPhone game “Wordly” are dialogs that appear modal to the user, but are non-blocking from the programmer perspective. For example, let’s take UIAlertView.

You tell a UIAlertView to show itself and the user sees a modal dialog, but the code after your show message keeps executing, before the user even clicks anything. The way to find out which button the user clicked is via a callback; the UIAlertView calls the alertView:clickedButtonAtIndex: method of the delegate object (an object that conforms to the UIAlertViewDelegate protocol) that you supply.

So using the calling object as the delegate, it looks something like this:

A few things bother me about this style:

  1. Displaying a modal dialog and then reacting to the choice is conceptually a simple, sequential process, but you end up splitting your steps between two methods. The first method doesn’t even mention the name of the second method, so for programmers who are unfamiliar with Cocoa or just forgetful of what the magic method is in UIAlertViewDelegate, it’s not immediately clear how the code flows.
  2. To decide how to handle a button press, you have to match against a button index or a button title that you used in the other method. This is in my mind a violation of the DRY principle and it’s error prone.
  3. If your class is the delegate for a bunch of dialogs, stuff starts to get messy pretty quickly, as your method needs to distinguish between different dialogs by looking at the alert view’s tag or otherwise inspecting it.

Basically, it’s not as readable as I would like. It seems I am not alone:

Interestingly, the authors of the latter two blog posts also develop solutions that are similar to my first solution below. I’ve not yet found anything that looks like the second solution that I discuss below.

My first idea for how to make things more intuitive was to create a new class called ModalAlertView. Basically it just polls in a while loop, until the callback gets called. NSRunLoop‘s runUntilDate method is used in the while loop to let the event loop process events – here’s the relevant part of the code:

Now you can use this modal dialog something like this:

This seems to work pretty well, but it still bothers me. Polling is wasteful and we’re talking about mobile devices here, so we’re wasting processor time and battery life and when we have multitasking in iPhone OS 4, this will be wasting time that other processes could be using. The API also seems to really be pushing the developer in the direction of having non-blocking code and this approach kind of subverts that. I’d rather not go against the grain.

So I searched for another solution. For a while I thought the problem I was trying to solve was how to create a modal dialog. But then it dawned on me that the real problem was that I wanted a more intuitive way to create and react to dialogs. Making the dialog modal was one way to make things more intuitive to my sequential brain, but there was perhaps another way.

The other way was to create a class that displays the dialog and then acts as the delegate for that dialog, doing dispatching to whatever methods the caller specifies for the buttons, thereby relieving the caller of the responsibility of doing the dispatching. The caller uses the new API like this:

Concise. Simple. And it can be implemented with pretty simple Objective-C, without funky polling and run loops. Here’s what the implementation looks like:

Nothing too hairy in there, that I can see.

It gives you a simple API that lets you create buttons and link them to specific handler methods. You don’t even need to worry about releasing the dialog object as it adds itself to the autorelease pool after the callback fires.

Objective-C afficionados, please send me any suggested improvements…

Xcode/iPhone error 0xE8000001: problem and fix

As you all probably know, I’ve written a word game for the iPhone called Word Up!

<shameless-plug>
reacquainted - 288 points
</shameless-plug>

Tonight, I started getting an error while trying to run my app from Xcode on my device (provisioned for development). The error was:

Your mobile device has encountered an unexpected error (0xE8000001)
during the install phase: Copying file.
Try disconnecting and powering off the device; then power the device
on and reconnect it.

I tried resetting the device a number of times and rebooting my MBP as well to no avail. It was beginning to look like I was going to have to do the dreaded restore and then lose all the cool jailbreak stuff that I’ve become so accustomed to. And then that made me remember that because my device is jailbroken, I can ssh to it and poke around. I wondered if a previous failed copy left some garbage on the device that was causing subsequent copies to fail.

iPhone:/ root# find . -name 'Word Up*'
./private/var/mobile/Media/PublicStaging/Word Up!.app
iPhone:/ root# cd /var/mobile/Media/PublicStaging/
iPhone:/var/mobile/Media/PublicStaging root# rm -rf Word\ Up\!.app/

Bingo. That fixed it. So if you hit this problem and you happen to have access to the filesystem of the device, give it a shot.