More of a programming nerd than is strictly healthy. See also {nevyn.nu, thirdcog.eu, twitter}

Projects

Overooped

UIKit: Hide the keyboard without a reference to the currently focused text field

Googling for answers to UIKit or iOS/iPhone programming problems today resembles googling for answers to JavaScript problems. There is so much horribly, horribly broken code out there, being promoted as the way to do things. Ranting aside, today’s problem is writing your own view controller container, and noticing that focused UI elements don’t dismiss their keyboard in response to viewWillDisappear: or similar. If this was MacOS, or AppStore approval didn’t exist, you’d just do [self.view.window.firstResponder resignFirstResponder]. You can’t do that though, firstResponder is private on window, don’t ask me why. cdyson37 on StackOverflow however, found the public API -[UIView(UITextField) endEditing:] hidden in a category in UITextField.h, that supposedly looks recursively through the receiver’s children for the first responder, and if found, resigns it. Perfect! A copy-pasteable code snippet for lazy googlers:

[self.view endEditing:YES]

Howto: Restore Springboard icon positions after iTunes botches them

You’re syncing from another computer. You’re restoring from a backup. iTunes has a bad day. Whatever reason, iTunes decided to resync all your apps, and replace them in your springboard in alphabetical order. I don’t know about you, but I don’t find that particularly helpful. I don’t know *how* many times I’ve meticulously sorted at least the three first Springboard pages with my most often used apps (which doesn’t sound like much, but *damn* does that UI suck!).

Expert instructions
Get your ~/Library/Preferences/com.apple.springboard.plist from your old device or a backup, and replace the plist on your new device or new install. Nothing of much importance is in that file, so it should be fine to just replace. If you’re worried, just open the two files in Property List Editor and copy the array over; it’s just an array of array of application identifiers under the keypath iconState.iconLists. Respring/`killall SpringBoard` when done.

Noobie instructions
Scenario: You have a recent backup of your phone/pod/pad in Time Machine. You have your device with the botched icon ordering. You want to fix things.

  1. Make a backup of your device. This way, we will know relatively certainly which backup belongs to this particular device.
  2. In Finder, navigate to your home folder > Library > Application Support > MobileSync > Backups
  3. Sort by Modified, newest at the top. The topmost one (something like “74e39ee0ac6b69af6f57e213cf5c6b95e5fd787f”, perhaps longer and with dashes) will be your device’s backup. Move this one to your desktop.
  4. Enter Time Machine for this folder. Restore the folder you moved away before to yesterday’s version or something
  5. Download the iPhone Backup Extractor app
  6. Open that app, click the button, choose the name of your device with the most recent date, and confirm
  7. At the bottom, there is an “iPhone OS Files” entry. Extract this to your desktop.
  8. Now, your device need to be jailbroken. If it isn’t already, get Spirit JB, run it, and jailbreak your device (it’ll only take seconds)
  9. If you just jailbroke your device, or if you don’t have SSH enabled, go into Cydia on your device, wait for it to restart, and then install OpenSSH. You must change your default password, or bad things will invariably happen.
  10. Get Transmit or another good SFTP client.
  11. Make sure you’re on the same wifi as your device.
  12. In your SFTP client, connect to (name of your device, with spaces replaced with dashes).local. My device is called Canvas, so I connected to Canvas.local. The connection method should be SFTP, the username should be ‘mobile’, and the password is your mobile password, as changed above or previously. By default it is ‘alpine’, but you REALLY SHOULD NOT USE THIS PASSWORD, as it means anyone can connect to your phone, and e g read and send SMSes.
  13. You’ll end up in your mobile user’s home folder. Navigate to Library > Preferences.
  14. From your desktop, get the file iPhone OS Files > Library > Preferences > com.apple.springboard.plist, and upload and replace the one on your device.
  15. Respring or reboot the device. Icon positions should be restored.

I haven’t tested the noobie instructions; just mail me at joachimb@gmail.com if they don’t work and we’ll figure it out.

On ngmoco’s We Rule

We Rule is a pretty boring FarmVille knock-off for iPhone and iPad. Actually, it’s really well made for what it is: nice graphics, music and atmosphere. But all you do is plant, harvest, order and deliver. I figured, maybe I can enjoy it anyway? One of the results from that is the image below.

It’s obvious ngmoco are rewarding people who spend as much time as possible in the game. The fastest way to get money is to plant the fastest crop, so that you’ll have to constantly stay in the game — 6 coins per minute. The casual gamer might plant beans and return once a day, but only get 0.3 coins per minute.

Seeing someone with a nice kingdom doesn’t mean that they are dedicated, however. If you give ngmoco real, actual money and buy ‘mojo’, they’ll shorten any waiting time to mere seconds. I understand that this is their entire business model, but I feel it takes away from any sense of accomplishment of doing things the non-paying way.

What really annoys me is what this game could have been. The makers of the game, Newtoy, helped make Age of Empires 2, so obviously they know how to make non-casual games too. I tcpdumped the server traffic and got a json description of my kingdom, which was highly interesting. They planned for several kinds of resources: stone, food and wood, which would have made for a much more complex and interesting gameplay. The best part, however, is how the json hints at armies; infantry, archers, cavalry. This game would have been absolutely *kickass* if you could attack other players! Or attack anything at all, for that matter. There is also hints of trading, another absent feature.

Perhaps these features are scheduled for a future release? I dearly hope so, but I really doubt it. I imagine Newtoy had great plans for a social medieval strategy and city-building game, and came to Ngmoco for financing. However, Ngmoco must have found the game much too inaccessible to all the casual FarmVille gamers out there; what’s the fun in building if it can be torn down? And however do you get ROI on a freemium game without heaps and bounds of casual gamers? And thus did Kingdoms (production name) become We Rule.

(I’m nevyn on Plus+ btw, if you want to add me)

Filtering a UITableView, and keyboard wonkiness

Hey, another bug that took half a day to fix. That always deserves a blog entry.

So I have a UITableView, and on it I have a tableHeaderView containing a UISearchBar. The UISearchBar filters the contents of the UITableView, and thus at every key press I have to reloadData (or more specifically, I -[UITableView reloadSections:withRowAnimation:]). For some reason, this calls setUserInteractionEnabled:NO on the UITableView, which in turn makes the UISearchBar’s UIFieldEditor resignFirstResponder, which makes the keyboard collapse. After the reload, user interaction is restored, UISearchBar gets focus, and the keyboard comes up.

This is rather embarrassing: I even subclassed UITableView, disabling setUserInteractionEnabled, before I realized that right there, before my eyes, is a UISearchBar delegate method called -[UISearchBarDelegate searchBarShouldEndEditing:]. Just add a bool ivar to the view controller saying whether the search bar may be resign key, set it to false before refreshing, refresh, and set it to true, and in the above delegate, return the ivar bool. Done, no more disappearing and reappearing keyboards.

Oh, and the code:


- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
	_searchBarMayResign = NO;
	[self.tableView reloadData]; // or equivalent
	_searchBarMayResign = YES;
}
- (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar;
{
	return _searchBarMayResign;
}

 The write-compile-test cycle is very very tedious when doing iPhone development on the device, because the “compile” step needs to include “install on device”, which can be very, very slow. It can take up to a minute, depending on how many apps you have installed and the current cycle of the moon. Imagine, then, doing tiny interface changes and you want to see how that tiny fix changes the UI (which sometimes you really need to do on the device to get a feel for it) — ten tries changing an animation delay could mean ten minutes of just waiting for installation. If you’re jailbroken, there is an easier faster way.

In Cydia, install ldid, rsync and ssh
Follow this guide to install an ssh key pair on your iPhone, so that the script can install the app without asking for password.
Add an additional build target to your app, and call it “Upload” or something.
Make that build target depend on your real app (as in the picture above)
Add a “run shell script” build phase, and give it this script:
export DEVICE_NAME=Mishimazu.local
rsync -avz "${CONFIGURATION_BUILD_DIR}/${PROJECT}.app" root@${DEVICE_NAME}:/Applications/
ssh root@${DEVICE_NAME} ldid -s "/Applications/${PROJECT}.app/${PROJECT}"
Replace “Mishimazu” with the name of your iPhone.
Change your active target to “Upload”, and build as usual.
A few notes though.
This script does not launch the app, you’ll have to do that yourself.
You don’t get the console routed to Xcode. Open up the Console in the Organizer for a workaround (not as good though)
Xcode debugger won’t work
File locations might have changed! You no longer have your private uuid bundle with your documents, but rather need to place documents and related things in /var/mobile. It’s possible NSSearchPathForDirectoriesInDomains will figure the right paths out for you, I haven’t tested; just make sure you’re aware of this
You are no longer sandboxed. This might change assumptions you do in code


In short, only use this deployment method for simple things, and install as usual when you need to really make sure things still work as they should, before a beta or appstore deploy. Of course, if you’re targeting the Cydia store or similar, that doesn’t apply.

The write-compile-test cycle is very very tedious when doing iPhone development on the device, because the “compile” step needs to include “install on device”, which can be very, very slow. It can take up to a minute, depending on how many apps you have installed and the current cycle of the moon. Imagine, then, doing tiny interface changes and you want to see how that tiny fix changes the UI (which sometimes you really need to do on the device to get a feel for it) — ten tries changing an animation delay could mean ten minutes of just waiting for installation. If you’re jailbroken, there is an easier faster way.

  1. In Cydia, install ldid, rsync and ssh
  2. Follow this guide to install an ssh key pair on your iPhone, so that the script can install the app without asking for password.
  3. Add an additional build target to your app, and call it “Upload” or something.
  4. Make that build target depend on your real app (as in the picture above)
  5. Add a “run shell script” build phase, and give it this script:
    export DEVICE_NAME=Mishimazu.local
    rsync -avz "${CONFIGURATION_BUILD_DIR}/${PROJECT}.app" root@${DEVICE_NAME}:/Applications/
    ssh root@${DEVICE_NAME} ldid -s "/Applications/${PROJECT}.app/${PROJECT}"
  6. Replace “Mishimazu” with the name of your iPhone.
  7. Change your active target to “Upload”, and build as usual.

A few notes though.

  • This script does not launch the app, you’ll have to do that yourself.
  • You don’t get the console routed to Xcode. Open up the Console in the Organizer for a workaround (not as good though)
  • Xcode debugger won’t work
  • File locations might have changed! You no longer have your private uuid bundle with your documents, but rather need to place documents and related things in /var/mobile. It’s possible NSSearchPathForDirectoriesInDomains will figure the right paths out for you, I haven’t tested; just make sure you’re aware of this
  • You are no longer sandboxed. This might change assumptions you do in code
  • In short, only use this deployment method for simple things, and install as usual when you need to really make sure things still work as they should, before a beta or appstore deploy. Of course, if you’re targeting the Cydia store or similar, that doesn’t apply.

Warning: When replacing the glass on an iPhone 3G, don’t use pdaparts.com’s video!

Pdaparts.com has a video showing how to replace the glass on an iPhone 3G. These instructions are INVALID and will risk destroying your LCD. Please look at leewaterman’s HD video instead.

Specifically, what Pdaparts do wrong is they try to remove the LCD from the frame by loosening it from the bottom, breaking it free from the frame. However, the latches holding the LCD in place are placed along the edges. If you pry too hard along the bottom, you will break the crystals in your LCD! This will look like slightly colorful ink or oil blots where and near where you applied too much pressure.

The correct procedure is to unhinge the latches along the edges. leewaterman’s video shows exactly how this is done.

My brother needed some math homework help figuring out quadratic equations. I really want to teach him programming and I’ve shown him some very basic C before, so together we threw together a quick app solve quadratic formulas with the pq-formula :) [note: he chose project name :P]

(If you are a beta tester for any of my apps, you can even download and install the app and try it yourself!)

My brother needed some math homework help figuring out quadratic equations. I really want to teach him programming and I’ve shown him some very basic C before, so together we threw together a quick app solve quadratic formulas with the pq-formula :) [note: he chose project name :P]

(If you are a beta tester for any of my apps, you can even download and install the app and try it yourself!)