Our DNA is written in Objective-C


Simon asks:

I would like to loop through variables whose names end with numbers 0 to 5. What is the correct syntax for the i? I have tried variable[i], variable + i, without success

I know two methods to achieve this:

1. Put your objects into an array and then enumerate or for-loop over those

// e.g. in awakeFromNib
playerNameLabels = [[NSArray arrayWithObjects:player1NameLabel, player2NameLabel, player3NameLabel, nil] retain];
for (i=0;i<3;i++)
     UILabel *nameLabel = [playerNameLabels objectAtIndex:i];
     // do something the the nameLabel

2. Use the Key-Value-Coding approach.

// in this object's header the strings are defined, here we intialize them
string1 = @"string1";
string2 = @"string2";
string3 = @"string3";
int i;
for (i=1;i<3;i++)
     NSString *aName = [NSString stringWithFormat:@"string%d", i];
     NSString *oneString = [self valueForKey:aName];
     NSLog(@"string %d is '%@' and has length %d", i, oneString, [oneString length]);

The dangerous thing about the latter might be that you have construct precisely the right name for the value. Or else you will get an exception:

*** Terminating app due to uncaught exception ‘NSUnknownKeyException’, reason: ‘[<selectortestAppDelegate 0x524e80> valueForUndefinedKey:]: this class is not key value coding-compliant for the key string0.’

But actually the second approach is how Cocoa does most KVC internally.

LuckyWheel Garners Favorable Reviews

It’s only a couple of days since LuckyWheel was approved for sale on the App Store.

The first few sites that linked to the store where clearly automatic robots. iTunes gets its information in XML plist format and a couple of sites came into existence that do nothing but parse this information

I don’t know what effect those will have on sales. They might just be a modern form of spam blogs.

But what really made my day was finding a review on FingerGaming. LuckyWheel went public on the same day as “Wheel of Fortune” by Sony which aims to mimic the mechanics of the TV show by the same name. In contrast we did not try to copy something, but create a unique approach. Make a game that uses the strength of the touch interface and fill it up to the brim with proverbs in English, German, Spanish, French, Italian and Dutch.

They say:

“LuckyWheel additionally boasts a feature that Wheel of Fortune doesn’t include in any capacity — a fully fledged German-language option, complete with a localized puzzle selection full of German proverbs.”

“[…] LuckyWheel offers gameplay variety that Wheel of Fortune could never dream of.”

“LuckyWheel is a good protest purchase if you want to voice your disappointment in Wheel of Fortune[…]”

Next up in mostly positive feedback was iPhone App Reviews.net. This was the only site that actually also allowed for giving away a couple of free promo codes to their mostly US-based readers.

They say:

[…] LuckyWheel can really be pretty fun when you’re with a friend or two and having a little pass-n-play competition.

[…] Drobnik is committed to developing LuckyWheel to be as good as (or better than?) Sony’s game

Everyone who likes this kind of word puzzle but isn’t married to the TV format, get LuckyWheel. Despite its shortcomings, LuckyWheel is decent for $1.99 and hopefully it’ll grow into something that can really compete with an established franchise.

Just as welcome as professional reviews are comments by the users themselves

Chris: “I like the game. I have also tried Wheel of Fortune from Sony and have more fun playing LuckyWheel. Not because it is now free. I hope that there are more people who think the same.”

Peter: “I have also tested both games and have come to the result that LuckyWheel is the better one. Surely the graphics are not as beautiful, but why spend $4.99. So why not support LuckyWheel. Maybe a spin button would be nice, but I like spinning the wheel rather.”

We still have some promo codes available, valid on the US app store which we’ll happily provide to anyone who would like to write a review about any of our applications.

Also note that the next version has already been submitted to Apple and increases the guessing fun to all of these languages: English, German, Italian, Spanish, French and Dutch.

Drawing Text in Graphics Contexts

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.

- (void)drawRect:(CGRect)rect {
	CGContextRef ctx = UIGraphicsGetCurrentContext();
	CGContextSetRGBFillColor(ctx, 1, 0, 0, 1);   // inside red
	CGContextSetRGBStrokeColor(ctx, 0, 1, 0, 1);  // outline green
	double text_angle = -M_PI/4.0;  // 45 Degrees counterclockwise
	CGAffineTransform xform = CGAffineTransformMake(
		cos(text_angle),  sin(text_angle),
		sin(text_angle), -cos(text_angle),
		0.0,  0.0);
	CGContextSetTextMatrix(ctx, xform);
	CGContextSelectFont(ctx, "Helvetica", 20.f, kCGEncodingMacRoman);
	CGContextSetTextDrawingMode(ctx, kCGTextFillStroke);
	CGContextShowTextAtPoint(ctx, 100, 100, "Test Text", 9);

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.

Angle of a Vector

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:

- (CGFloat)angleFromPoints:(CGPoint)pos1 otherPoint:(CGPoint)pos2
    CGPoint vector = CGPointMake(pos1.x-pos2.x, pos1.y - pos2.y);
    double angleCalc;
    if (vector.y &lt; 0)
        // upper Half
        angleCalc = atan2(-vector.y,vector.x);
        angleCalc = atan2(vector.y,-vector.x)+M_PI;
    return angleCalc;

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.

iPhone OS 3.0 for Developers

Today the typical dev-geek was glued in front of his web browser to get as much information as possible on the pending release of the next version of the operating system that powers all touch-enabled devices under the Apple brand. I stuck with the major two, Gizmodo and Engadget, especially because those two by now have mastered the art of interspersing illustrative photographs amongst concise journalistic commentary.

Apple claims that there are 1000 new API’s coming in 3.0 that they have been busily developing over the last year. An impressive number of news by any rate and it was put to the test by the scrutiny of many an iPhone user who threatens to leave the platform for Android because of the lack of cut&paste, stereo bluetooth, tethering, background processes and the like.

Most of those deficits will be remedied in OS 3.0, or so it seems. With an Apple twist. Background processes, no way. But amazing notification infrastructure, that is nicer to stand-by times anyway, yes. Pay no attention to the man behind the curtain! Just watch and be amazed at the magic with the Apple.

As a developer I paid really close attention to what new features might work in my existing or future apps. The single most important thing I found was cut&paste. As simple as this might sound, even “standard”, as numerous are the uses I can imagine for it.

The guys on stage kept dealing out new APIs and features as if they where handing out candy.

  • Turn-based navigation will be possible … if the creator brings his own maps. Garmin, where are you?
  • “Stereo Bluetooth” aka. A2DP. Finally wireless music to my ears.
  • MMS, send voice memos, locations, vCards to other phones
  • “Spotlight” a seperate screen that searches everything on the device, even apps
  • Multiple Calendars with synching, especially noteworthy: CalDAV
  • Voice Memos, also with an external Microphone
  • Cut and Past, Shake to Undo. Copy full paragraphs e.g. from Safari
  • Push Notifications will finally enable a slew of multi-system IMs
  • Much improved Video Streaming capability with automatic best rate adaption

Lots of new APIs in OS 3.0

The bits that I thought most interesting to developers:

  • in-app e-mail support, maybe the end of the attachment shortcoming?
  • Shake API, no longer do I have to code this myself?
  • access to the users music library on the phone, probably also the voice memos
  • use the push notification API to invite other people to activites, e.g.games
  • USB/Bluetooth external-device API might allow for interesting add-on hardware possibilities
  • In-App Purchaes (iAP)! From within the app you can sell new game levels or other content
  • Access to the Proximity Sensor
  • Battery information API – maybe apps can now be smarter about how much CPU and energy they use
  • In-Game Voice – wow, about an online-multiplayer LuckyWheel that lets people talk to each other?
  • And many minor tweaks to existing classes UIAlertView, UITableView, table cells, etc.

Still there were so many more buzzwords that did not get treated with an explanation. Or do you know that those are?

  • Core Data – a new API for handling data? A nicer way to interact with Sqlite?
  • Localized Collation – Digital Alphabet Soup?
  • GPS Lingo – are they going to put even cooler GPS buzzwords into the SDK?

"We'll be back soon" says Apple while the update the developer site.

It still remains to be seen behind all these cool announcements how much liberty and creativity Apple will actually permit it’s developers to have. All these new features are really quite overwhelming for us small-time developers and it remains to be seen who of us can embrace them quickly.

Did anybody get to 1000 counting new announcements? I did not, but I am still excited.

It was also announced today that there would be a BETA available for paying developers. So far I cannot report anything about that because we are greeted with the usual “We’ll be back soon” because most likely the developer site is totally overrun by people hungry for more info.

In summary I am glad that Apple today showed that they are taking the touch platform seriously and they are willing to put in extra work to catch up to other platforms that boast many features where the iPhone fell behind. I feel reassured that I can relax and stick to developing for the iPhone because with all those shortcomings finally getting remedied the market of my potential customers will continue to grow for the foreseeable future.

GeoCorder 1.0.2

<a href="http://www.cocoanetics.com/index.php/geocorder/"GeoCorder 1.0.2 is now publicly available.

New Features:

  • added option to continue a recording
  • added icon for tracks in track overview


  • Changed all trackpoint times to UTC as per GPX spec
  • removed HDOP and VDOP digits right of comma
  • added proper time sorting of trackpoints in exported tracks

Localization Workaround

Trebor asks:

“When I add a new localization, there are just a few choices:





I thought that the system needed “fr” to know it is French and “de” to know it is German?

Will it recognize the word “German” and know that is the same as a de.lprog?

If the answer is yes, does it know the full names of all languages?

For example, if I want to add Chinese, can I call the localization “Chinese” or do I need to call it zh?”

I believe the following to be true. Xcode is still putting in English as first localization if you make a file localizable. This works, but the “modern way” to do things (or so I read) is to use the two letter iso codes. The problem is, that if you remove the English then you can never add any new localization. That’s a bug in Xcode.

So I do it like this:

  • create the file
  • make it localizable
  • add localizations for all locales you require, including English: en, de, it, es, fr, nl
  • LEAVE English empty, but put English into the “en” locale

Do not remove the “English”, because then XCode will not allow you to add new localizations in the future.

NSArray Sorting

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.

// first you need to set up the descriptor
NSSortDescriptor *firstDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"firstField"
							 ascending:YES] autorelease];
NSSortDescriptor *secondDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"secondField"
							ascending:YES] autorelease];
NSArray *sortDescriptors = [NSArray arrayWithObjects:firstDescriptor, secondDescriptor, nil];
NSArray *unsortedObjects = [NSArray arrayWithObjects:oneObject, secondObject, nil];
// new and shiny sorted array
NSArray *sortedObjects = [unsortedObjects sortedArrayUsingDescriptors:sortDescriptors];

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.

//  MyOwnClass sort function
- (NSComparisonResult)compareByTime:(MyOwnClass *)otherObject
	NSTimeInterval diff = [self.timestamp timeIntervalSinceDate:otherObject.timestamp];
	if (diff&gt;0)
		return NSOrderedDescending;
	if (diff&lt;0)
		return NSOrderedAscending;
	return NSOrderedSame;

Once you have it set up like this sorting is as easy as:

// original unsorted array
NSArray *unsortedObjects = [NSArray arrayWithObjects:oneObject, secondObject, nil];
// new and shiny sorted array
NSArray *sortedObjects = [unsortedObjects sortedArrayUsingSelector:@selector(compareByTime:)];

Here is another example that uses the compare method that’s built into NSString:

NSArray *unsortedArray = [NSArray arrayWithObjects:@"String3", @"String2", @"String1", nil];
NSArray *sortedArray = [unsortedArray sortedArrayUsingSelector:@selector(compare:)];

Sorting is very simple with the two methods shown above. If you just want simple sorting then use descriptors. If you need more control over the sorting method then define your own sorting method.

Retain, Release … repeat

In Objective-C you have to make sure that you match your alloc and retains with the appropriate number of release calls. Otherwise you might be leaking objects. Here’s an example that I faced today.

The normal pattern if you create an object that you then add to an array is the following:

Player *tmpPlayer =  [[Player alloc] initWithName:player1Name.text color:[UIColor greenColor]];
[tmpArray addObject:tmpPlayer];
[tmpPlayer release];

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:

- (id) initWithName:(NSString *)aName;
		if (self = [super init])
			self.name = aName;
			NSLog(@"player %@ init, retain count is now %d", name, [self retainCount]);
			return self;
	return nil;
- (void) retain
	NSLog(@"player %@ retain, retain count is now %d", name, [self retainCount]+1);
	[super retain];
	// cannot log here, causes crash
- (void) release
	NSLog(@"player %@ release, retain count is now %d", name, [self retainCount]-1);
	[super release];
	// cannot log here, causes crash
- (void) dealloc
	NSLog(@"player %@ dealloc", name);
	[name release];
	[super dealloc];

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.

Localization Woes

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.

// without localization
player1Name.placeholder = @"Player 1";
// with localization
player1Name.placeholder = NSLocalizedString(@"Player 1", @"Player View");

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.

# in your project directory
genstrings Classes/*.m

The strings file will look like this:

/* Player View */
"Player 1" = "Spieler 1";
/* Player View */
"Player 2" = "Spieler 2";
/* Player View */
"Player 3" = "Spieler 3";

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.