Tuesday, October 20, 2009

Objective-C Tuesdays: The for...in loop

We've looked at the standard for loop for the last two weeks. This week we will dive into the for...in loop introduced in Objective-C 2.0. Unlike the standard for loop, the for...in loop is not available in plain old C.

In Objective-C, collection classes such as NSArray, NSSet and NSDictionary are a key part of the Objective-C Foundation framework. Collections provide high level ways to group and organize objects.

In older versions of Objective-C, looping over items in a collection is done using an NSEnumerator object in a while loop:
NSSet *items = [NSSet setWithObjects:@"foo", @"bar", nil];
NSEnumerator *enumerator = [items objectEnumerator];
NSString *item = nil;
while (item = [enumerator nextObject]) {
  // do something with item
}
It's possible to loop over items in a NSArray using a standard for loop, since NSArray has a well defined order:
NSArray *items = [NSArray arrayWithObjects:@"foo", @"bar", nil];
for (NSUInteger i = 0; i < [items count]; i++) {
  NSString *item = [items objectAtIndex:i];
  // do something with item
}
Unfortunately, some collection classes (such as NSSet) don't have a well defined order; NSEnumerator used to be the only option.

The for...in loop works on any collection that conforms to the NSFastEnumeration protocol (all the standard ones do). The for...in loop is similar to a standard for loop but simpler. Instead of the three sections of a standard for loop, there are two, the loop variable and the collection expression:
for (loop variable in collection expression) {
  // do something with loop variable
}
Loop Variable The loop variable can be a previous declared variable:
NSString *item = nil;
// ...
for (item in collection expression) {
  // do something with item
}
or it can be declared inside the parentheses:
for (NSString *item in collection expression) {
  // do something with item
}
Collection Expression The collection expression can be any expression that evaluates to an object conforming to NSFastEnumeration. Typically, this is simply a collection variable defined elsewhere:
NSSet *items = [NSSet setWithObjects:@"foo", @"bar", nil];
// ...
for (NSString *item in items) {
  // do something with item
}
but can be a function call or method call:
for (NSString *item in [NSSet setWithObjects:@"foo", @"bar", nil]) {
  // do something with item
}
Dictionaries When using a for...in loop with a NSDictionary, the loop variable receives the dictionary keys; to work with the dictionary values inside the loop, use objectForKey:
NSDictionary *numbers = [NSDictionary dictionaryWithObjectsAndKeys:
    @"zero", @"0", 
    @"one", @"1", 
    nil];
for (NSString *key in numbers) {
  NSString *value = [numbers objectForKey:key];
  // do something with key and value
}
Mutation Guard Modifying a collection while iterating over it can cause very unintuitive behavior, so the for...in loop uses a mutation guard behind the scenes. If items are added or removed from a collection while your for...in loop is running, an exception is thrown. This is generally a good thing, but it makes filtering a collection somewhat tricky:
NSMutableSet *items = [NSMutableSet setWithObjects:@"", @"a", @"aa", @"aaa", nil];
for (NSString *item in items) {
  if (item.length < 2) {
    [items removeObject:item]; // WARNING: exception thrown on mutation
  }
}
The way to get around this restriction is to iterate over a copy of the collection and modify the original (or vice versa):
NSMutableSet *items = [NSMutableSet setWithObjects:@"", @"a", @"aa", @"aaa", nil];
for (NSString *item in [[items copy] autorelease]) {
  if (item.length < 2) {
    [items removeObject:item]; // OKAY: looping over copy, changing original
  }
}
Next week, we will look at the while loop.

Monday, October 19, 2009

Orchard's Craps - Preview Video

We have a "preview" video of Orchard's Craps available for you to view here or on our Able Pear YouTube Channel.  There are review and walk-though videos coming soon... stay tuned...



Orchard's Craps is available at the App Store for the iPhone and iPod touch and we have a FREE version of Orchard's Craps for the PC and Mac.

The two App Stores

Marco Arment, the lead developer of Tumblr, wrote a great post recently about the two different types of App Store customers and how to match your app to the type of customers you're looking to attract.
These two stores exist in completely different ecosystems with completely different requirements, priorities, and best practices.

But they’re not two different stores (“Are you getting it?”). There’s just one App Store at a casual glance, but if you misunderstand which of these segments you’re targeting, you’ll have a very hard time getting anywhere.
Read more about The two App Stores.

Friday, October 16, 2009

iPhone Friday - October 16, 2009

Hello and happy Friday. Todays set of wallpapers come from Japanese Design (Dover Pictura) which is part of a collection of books including Chinese Design and Art Deco just to name a few. I highly recommend them as they are beautiful, inspiration and (within their terms) royalty-free. Have a great weekend!








Thursday, October 15, 2009

In App Purchase now available for free apps


Apple announced today that developers can now use In App Purchases in their free apps.  This not only unlocks a new revenue stream for several existing free apps but also paves the way for a new type of "lite" version of a app.  No more downloading an app to test it only to have to download the "for pay" version.  ("One app to rule them all" - LOTR quote... really!)

Apple also says this should help combat some of the problems of software piracy by allowing you to verify In App Purchases.

To learn more, log into your Apple iPhone Developer account and visit the App Store Resource Center.

If you are a developer currently looking into using In App Purchases in your existing or upcoming fee iPhone/iPod touch app, we'd love to hear from you on your new experience.  Cheers!

App Store Heresies: Higher Price, Better Ratings.

Dan Grigsby of Mobile Orchard presents an interesting argument against discounting your app, particularly when you first launch:
Furthermore, the likelihood of a 1-star review goes up as the price goes down: 1-star ratings made up 23% of the total number of ratings in the free group; 16% in the paid group.
Read App Store Heresies: Higher Price, Better Ratings. Don’t Discount Your App At Launch.

Tuesday, October 13, 2009

Objective-C Tuesdays: for loop variations

Last week, we examined the structure of the for loop. Today we will look at some for loop idioms.

Infinite loop If you omit the initialization, condition and action expressions, you get an infinite loop:
for (;;) {
  NSLog(@":-)");
}

Missing loop expression Sometimes, there's no need to initialize a variable before looping, so the initialization expression is omitted:
char *process_line(char *buffer) {
  for ( ; *buffer != '\n'; buffer++) {
    /* do something with characters */
  }
  return buffer;
}
Similarly the condition or action expressions are sometimes omitted.

Nested loops When building or processing tables of information, put one for loop inside another:
for (int i = 1; i <= 10; i++) {
  for (int j = 1; j <= 10; j++) {
    NSLog(@"%d X %d = %d", i, j, i * j);
  }
}

Parallel iteration You can use multiple loop counter variables by using the comma (,) operator to squeeze multiple expressions into initialization and action:
int i, j;
for (i = 0, j = 9; i < 10; i++, j--) {
  destination[i] = source[j];
}

There's a gotcha with the initialization expression however: only one loop counter variable can be declared there. It seems logical to do this:
for (int i = 0, int j = 9; i < 10; i++, j--) ...
but unfortunately you can only do this:
int j;
for (int i = 0, j = 9; i < 10; i++, j--) ...

Next week, we'll look at the Objective-C 2.0 for...in loop.