Category Archive for ‘Recipes’

Sometimes you might need to draw text instead of just using a comfortable UILabel. For example if you want to show it a a specific angle. This takes a lot of code, but once you understand it, it’s just copy and paste.

Of special importance is the application of a tranformation matrix via CGContextSetTextMatrix. Without it, your text will be drawn upside down. This is a feature, not a bug, because internally the iPhone still wishes that (0,0) is in the lower lefthand corner, but for most UIView-releated uses this is the “right way around”, i.e. (0,0) in the upper lefthand corner.

When dealing with a multi-touch rotation I was searching for a simple method to calculate the angle of two fingers. Well, actually more precisely the angle between the vector from one finger to the second finger and the horizontal X Axis.

While I was still searching my friend Christian Pfandler came up with this function:

The regular atan(x) function seem to have a limitation by only returning values between 0 and +/- PI. Because of this there is also the atan2(y,x) function which is orders of magnitude more useful. To get a continuos angle for the full circle we have to treat the upper half and the lower half seperately though. I found this here.

I don’t quite understand it, but it seems to work. Please keep in mind though that like all angles in Cocoa Touch this is in radians as well. So not 0…360, but 0…2*PI. If you know an even simpler method, please let me know.

If you need the contents of an NSArray in a different order than they where entered into the array you have several options available. By far the simplest is to use descriptions if you have a standard data type you wish to sort by. You first set up an array with the names of fields to sort by. Then you sort.

A little more involved but way more powerful is the method of using a selector. Here you add a function to your special class that you are keeping in the aray which takes care of deciding which of two object comes first: self or the other one.

Note that the sort method needs to be part of the class itself. You can make your sorting logic as complex as you like to using multiple sort methods. Cocoa Touch calls this method every time it needs to know the order of two objects. Having access to all the other object’s properties you can have your function return NSOrderedAscending, NSOrderedDescending or NSOrderedSame depending on what order you determine to be correct.

Because adding an object to an NSArray causes the object to be retained you have to religiously follow any addObject with a release. You only want to keep the object retained once because when you later release the array, the array in turn releases all it’s objects and if the retain count is higher then 1 then these objects will leak. I.e. their dealloc won’t be called because they still have a retain count higher than zero.

To visualize the dance of alloc, init, retain, release and dealloc you could do the following:

As you can see it is easy to override retain, release and dealloc and inject an NSLog to output the current retainCount. But don’t leave those log statements in the final product! NSLog are executed even if you strip all other debug info via a release build and I have seen them dramatically decrease your app’s performance.

In my case today I had forgotten the release after the addObject and thus the Instruments tool showed a couple of bytes leak that I spent an hour looking for in the wrong place.

Adding additional languages to your iPhone app is extremely easy. Below I’ll show you how. But there is one thing that the documentation did not mention, that also cost me a couple of hours.

Step 1: Change all strings to be localizable

You need to go through your code and everywhere you want a string to be localizable you need to change it to use the NSLocalizedString macro. This marks this string to be localized. Also if no localization can be found then the string returned is identical to the first parameter.

The second parameter is called “comment”, but it’s actually sort of a context for the “Player 1″ token. I would use this to uniquely identify the view where it’s used.

Step 2: Generate your Localizable.strings file

The SDK comes with a very useful tool genstrings. This tool scans your code for all instances of NSLocalizedString and pulls these together into a UTF-16 strings file. This file you can send to a translator who will change the replacements, in the end you will have one Localizable.strings file per language.

All strings on the right side of an equal sign should be changed. If you want to you can aggregate multiple tokens under one header if it is identical, but don’t change the comments because otherwise the NSLocalizedString will not work.

Step 3: Add strings file to your project and make it localizable

Now go into your project and add an empty Localizable.strings file. Right-click on it, Get info, and add localizations for all languages that you want to support. Note that Xcode adds “English” for you, but this is outdated: your locales should use the 2 letter ISO code. en for English, de for German and so on. So after adding those you should remove English.

This will create localization directories under your project directory that are called like de.lproj. Those directories contain all the language-specific variantes of all files for this language. You can even localize images like that.

Step 4: Troubleshoot

That’s all it takes… if you haven’t accidentially change the strings files away from UTF-16. Because then you will find that the build process for your app works fine, but on the device localization will fail to work. If you look into the app bundle your strings file will have been renamed like Localizable.strings.45601. Of course the iphone will be unable to find this file like this and instead use the default localization.

In the info of any strings file you can change and/or force it to UTF-16. Save yourself the pain of not knowing why your pretty new language does not show up. Another reason I found (which nobody warns you about) is those darn semicolons. Should you loose a single one you again don’t see your localization even though the building works fine. Been there, trust me.

In Summary, localization is really simple with Objective C. Seasoned programmers would probably even do step 1 while they are coding. It’s just a little bit more code, but the rest is almost automatic. Now all I need to do is find people who speak French, Spanish and Japanese.

Coming from the Windows world I was used to storing program settings into this beast that is known as “The Registry”. So when I came to iPhone I had no clue where to put those settings that you want to keep between program launches. My first instinct was to put them into an NSDictionary and save this to disk.

That’s how I did it for half a dozen programs only to realize today that there would have been an easier method. The magic class to do it all with is called NSUserDefaults. All you need to do is instantiate it and then read and write values for names of your choosing, just like you would interacting with a dictionary.

In reality you are interacting with an in-memory copy of your defaults. The documentation mentions that the system will synchronize it frequently with the persistent storage on disk. If you really want to make sure it gets written, like when your program is exiting, then you can call [defaults synchronize]. But that should not be necessary. In my tests that defaults where also successfully persisted if I changed them as late as in ApplicationWillTerminate.

Also great to know is that you are not limited to just keeping string values in your defaults. Any object that is legal for property lists can also be used in the defaults. These are: NSData, NSString, NSNumber, NSDate, NSArray or NSDictionary.

Note how you can directly retrieve the integer value with the convenience method integerForKey. To get an NSDate you need to use objectForKey, there is no dateForKey as one might assume.

Finally there is one more convenient thing. If the defaults get changed, a notification gets sent to which you can subscribe in multiple classes. This notification gets sent out for every single change, so if you change 4 values in a row, the notification will be sent 4 times.

There you have it. For any kind of settings you want to keep you can use the methods explained above and save yourself much work. For data that you need to keep secure (e.g. passwords) you will be better advised to use the keychain which I will explain in a future article.

You might be aware that the earth is in fact not flat but a globe with lots of time zones spread more or less evenly around its cirumference. There was a time when programmers had to do most of the heavy lifting of times and dates themselves, but luckily Cocoa has some nice classes to take care of the calculations for you.

Here is an example how I would “move” my birth date to the USA. What’s great about it is that it also seems to takes care of daylight savings time. In Austria and Germany this was only introduced 6 years after my birthday, so July 24th in 1974 has timezone GMT+1 whereas July 24th 1984 ends up with GMT+2.

Now you might wonder why the output from the NSLog is +0100 and +0200 and not the US timezone. The reason is that Cocoa internally will always automatically convert dates to your current system timezone.

Try it out for yourself? Create a date instance like I have shown above, log it, then change the default timezone for your program and log it again. Even though you did not modify the date instance, you will get a different output.

I have grown very fond of using NSDictionary and NSMutableDictionary if I want to put diverse data into a single object to pass around in my programs. Also NSDictionary has the built-in capability of saving and reading itself to disk, in the so-called property list (abbreviated as “plist”) format.

Now I was implementing caching of such a NSDictionary in my app and for mysterious reasons the following code would not result in any file being saved:

Can you spot the problem? Probably not, if you check the documentation you will read that NSDictionary can hold and save any of the following data types: NSNumber, NSData, NSString, NSDictionary, NSArray. I did not use anything else, therefore the dictionary should be saved as a plist. With lots of experimenting however I found a simple change to the above code that makes it work:

If you want to save a dictionary, make sure you use only strings for keys. In another case I was using an NSDate as valid key for an entry in a dictionary. Same result: writing it to a file does not work. Why there is such a limitation I cannot say. In any case I submitted it as bug report to Apple.

Having pondered this a little I realized the most probable explanation. If you look at the way an XML plist is represented in the file you can see that there is no indication as to what data type the represents. Therefore it can only be a string.

I found that I need some place to show a version in my apps, because otherwise I and my testers never know if we are talking about the same version. A problem they might be having could have already been fixed previously. Without a version info you are at a loss.

Here’s a version info box, that I came up with. This shows how to access the version string from Info.plist as well as open a new mail to the author.