Able Pear is happy to announce that our latest application, People?, is now available in the iTunes App Store.
People? is a game of questions and answers. Think of a person and People? tries to guess him or her.
Answer simple yes/no questions like "Is the person male?" or "Is he a US President?" When People? thinks it knows the answer it will guess the person: "Is it Barack Obama?"
When People? makes a wrong guess you can teach it the new person and add a new question to ask.
People? is great game for anyone age 8 and up who loves history and famous people.
Click here to see our complete list of apps.
Wednesday, December 30, 2009
Friday, December 18, 2009
iPhone Friday - December 18, 2009
Hello all and happy Friday! We've been busy here at Able Pear Software and we have some exciting news in the wings, waiting to be released to the (hopefully washed) masses. Today's iPhone and iPod touch wallpaper is from an upcoming game (and yes, there's only the one graphic). Enjoy!
Tuesday, December 15, 2009
Objective-C Tuesdays: global variables
Last time we finished up our series on looping with a look at common uses for
Any variable declared outside of a function or method, class
A global variable can be assigned an initial value when defined, but there's a tricky restriction: the initial value must be something the compiler can calculate at compile time. In general, this means you can only use literal values like numbers, characters and string literals, and you can only use basic numeric operators. Here are some examples of global variables with legal initial values:
Next time, we'll look at accessing global variables from multiple
goto
. Today we're starting a new series examining variables in Objective-C. Our first topic in the series is global variables.Any variable declared outside of a function or method, class
@interface
or struct
declaration is a global variable:int count1; // global int main(int argc, char *argv[]) { int count2; // local to main() ... }Initialization: By default, global variables are initialized to zero. For regular pointer types (including regular C strings) this means
NULL
is the default value; for Objective-C object pointers, it's nil
by default. (This is different than local variables, which don't have a guaranteed initial value and thus should always be explicitly initialized.)A global variable can be assigned an initial value when defined, but there's a tricky restriction: the initial value must be something the compiler can calculate at compile time. In general, this means you can only use literal values like numbers, characters and string literals, and you can only use basic numeric operators. Here are some examples of global variables with legal initial values:
int count; // defaults to 0 int daysPerYear = 365; int secondsPerDay = 24 * 60 * 60;Unfortunately you can't call functions or methods or use other global variables when assigning initial values. Here are some examples of illegal initial values for global variables:
// WARNING: WON'T COMPILE // ERROR: function call not allowed size_t titleLength = strlen("Objective-C Tuesdays"); // ERROR: method call not allowed NSUInteger subtitleLength = [@"global variables" length]; // ERROR: calculation uses other global variables unsigned long totalLength = titleLength + subtitleLength;This restriction generally means that global Objective-C object types can't be initialized when they're declared:
// WARNING: WON'T COMPILE NSArray *array = [[NSArray alloc] initWithObjects:@"one", @"two", nil];There is one exception:
NSString
global variables can be initialized with Objective-C string literals (those special @
strings):NSString *title = @"Objective-C Tuesdays";If you need to do some complex initialization on your global variables, your only choice is to do it explicitly when your program starts. There are a few common places to do this sort of work:
- at the start of
main()
- in your application delegate's
-init
method - in your application delegate's
-applicationDidFinishLaunching:
method - in the
+initialize
method of one of your classes
+initialize
method for that class is a good way to keep related code grouped together. Otherwise, -applicationDidFinishLaunching:
is commonly used in Cocoa-touch programs while the start of main()
is the traditional place in C programs.Next time, we'll look at accessing global variables from multiple
.m
and .c
files.
Objective-C Tuesdays: looping in Objective-C
Last week we wrapped up our look at the different ways to construct loops in Objective-C. Here's a quick overview of the posts.
There are four looping statements in Objective-C:
We examined the two loop flow modifiers:
Finally we wrapped up with a look at
Today, we start a new topic: variables.
There are four looping statements in Objective-C:
- the
for
loop - the
for...in
loop - the
while
loop - the
do...while
loop
for
loop is the most flexible; we looked at some for
loop idioms.We examined the two loop flow modifiers:
Finally we wrapped up with a look at
goto
and examined common uses of goto
.Today, we start a new topic: variables.
Friday, December 11, 2009
iPhone Friday - December 11, 2009
Hello and happy Friday. Today's collection of iPhone and iPod touch wallpapers were inspired from a friend (and you know who you are) asking me if I could do some that were a little lighter and seasonal. So the following four images are what I came up with I hope that you all enjoy them. Cheers!
Tuesday, December 8, 2009
Objective-C Tuesdays: common uses for goto
Last time we looked at the
Flow control: As we saw in previous weeks, the
Error handling:
Standard C doesn't have a concept of throwing and catching exceptions; it's normal for functions in C libraries to return a result code to indicate an error (or to have an out parameter that holds a result code or error object). Writing robust programs using a C API requires checking result codes at each step and taking the appropriate action. For example, a function to copy a block of data from one file to another might look like this:
Next time, a summary of looping and a new topic: variables.
goto
statement. Today we will look at the two common uses for goto
: flow control in nested loops and organizing error handing code.Flow control: As we saw in previous weeks, the
break
and continue
statements are used to modify the flow of execution in a loop. Both break
and continue
affect only the innermost enclosing loop. Sometimes you need to break out of nested loops. You could implement this with boolean flag values, but that approach can make your loop logic more convoluted and error prone. Instead, a goto
statement can be used like break
to jump out of nested loops:for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { if (...) { goto doneWithLoops; } } } doneWithLoops: // do more stuffSimilarly, you can use
goto
to emulate continue
within nested loops, though keep in mind that goto
doesn't automatically advance to the next item in a for
or for...in
loop the way continue
does:for (int i = 0; i < 10; i++) { start_j: for (int j = 0; j < 10; j++) { if (...) { i++; // manually advance loop counter to emulate continue goto start_j; } } }Along with its use in loops, the
break
statement is also used in the switch
statement to mark the end of a case
block. It's not uncommon to use a switch
statement inside a loop when implementing simple state machines, event dispatchers and parsers:// simple event dispatcher MyEvent *event = nil; while (event = getNextEvent()) { switch (event.type) { case KEY_EVENT: // handle key event break; case MOUSE_EVENT: // handle mouse event break; } } shutdown();Sometimes you want to exit the event loop from within one of the
case
blocks, like this:// simple event dispatcher MyEvent *event = nil; while (event = getNextEvent()) { switch (event.type) { case KEY_EVENT: // handle key event if (event.keycode == KEY_ESC) { // want to break out of the while loop // but a break here applies to the case block } else { // ... } break; case MOUSE_EVENT: // handle mouse event break; } } shutdown();You can always use a boolean flag variable and make your loop test more complex, but using
goto
here can make your code simpler and easier to follow:// simple event dispatcher MyEvent *event = nil; while (event = getNextEvent()) { switch (event.type) { case KEY_EVENT: // handle key event if (event.keycode == KEY_ESC) { goto event_loop_end; } else { // ... } break; case MOUSE_EVENT: // handle mouse event break; } } event_loop_end: shutdown();
Error handling:
Standard C doesn't have a concept of throwing and catching exceptions; it's normal for functions in C libraries to return a result code to indicate an error (or to have an out parameter that holds a result code or error object). Writing robust programs using a C API requires checking result codes at each step and taking the appropriate action. For example, a function to copy a block of data from one file to another might look like this:
void copy_block(char const *in_filename, char const *out_filename, size_t block_size) { FILE *in_file = fopen(in_filename, "r"); if (in_file) { FILE *out_file = fopen(out_filename, "w"); if (out_file) { char *buffer = malloc(block_size); if (buffer) { int bytes_read = fread(buffer, 1, block_size, in_file); if (bytes_read > 0) { int bytes_written = fwrite(buffer, 1, bytes_read, out_file); if (bytes_written == bytes_read) { [[NSNotificationCenter defaultCenter] postNotificationName:@"Copy block completed successfully." object:nil]; } else { [[NSNotificationCenter defaultCenter] postNotificationName:@"Unable to write to output file." object:nil]; } } else { [[NSNotificationCenter defaultCenter] postNotificationName:@"Unable to read from input file." object:nil]; } free(buffer); } else { [[NSNotificationCenter defaultCenter] postNotificationName:@"Unable to allocate buffer." object:nil]; } fclose(out_file); } else { [[NSNotificationCenter defaultCenter] postNotificationName:@"Unable to open output file." object:nil]; } fclose(in_file); } else { [[NSNotificationCenter defaultCenter] postNotificationName:@"Unable to open input file." object:nil]; } }This leads to deeply nested "flock of geese" code that can be error prone and hard to read. One technique to deal with this is to return from the function when an error is encountered. The same code implemented that way looks like this:
void copy_block(char const *in_filename, char const *out_filename, size_t block_size) { FILE *in_file = fopen(in_filename, "r"); if ( ! in_file) { [[NSNotificationCenter defaultCenter] postNotificationName:@"Unable to open input file." object:nil]; return; } FILE *out_file = fopen(out_filename, "w"); if ( ! out_file) { [[NSNotificationCenter defaultCenter] postNotificationName:@"Unable to open output file." object:nil]; fclose(in_file); // clean up return; } char *buffer = malloc(block_size); if ( ! buffer) { [[NSNotificationCenter defaultCenter] postNotificationName:@"Unable to allocate buffer." object:nil]; fclose(out_file); // clean up fclose(in_file); return; } int bytes_read = fread(buffer, 1, block_size, in_file); if (bytes_read <= 0) { [[NSNotificationCenter defaultCenter] postNotificationName:@"Unable to read from input file." object:nil]; free(buffer); // clean up fclose(out_file); fclose(in_file); return; } int bytes_written = fwrite(buffer, 1, bytes_read, out_file); if (bytes_written != bytes_read) { [[NSNotificationCenter defaultCenter] postNotificationName:@"Unable to write to output file." object:nil]; free(buffer); // clean up fclose(out_file); fclose(in_file); return; } [[NSNotificationCenter defaultCenter] postNotificationName:@"Copy block completed successfully." object:nil]; // clean up free(buffer); fclose(out_file); fclose(in_file); }One criticism of this approach is that clean up code is duplicated repeatedly and in different variations, a violation of the DRY principle. Some programmers also prefer to have a single return point in a function. Using
goto
, you can centralize clean up code in one place in the function (and as a side effect, the function now has a single return point):void copy_block(char const *in_filename, char const *out_filename, size_t block_size) { FILE *in_file = fopen(in_filename, "r"); if ( ! in_file) { [[NSNotificationCenter defaultCenter] postNotificationName:@"Unable to open input file." object:nil]; goto end; } FILE *out_file = fopen(out_filename, "w"); if ( ! out_file) { [[NSNotificationCenter defaultCenter] postNotificationName:@"Unable to open output file." object:nil]; goto clean_up_in_file; } char *buffer = malloc(block_size); if ( ! buffer) { [[NSNotificationCenter defaultCenter] postNotificationName:@"Unable to allocate buffer." object:nil]; goto clean_up_files; } int bytes_read = fread(buffer, 1, block_size, in_file); if (bytes_read <= 0) { [[NSNotificationCenter defaultCenter] postNotificationName:@"Unable to read from input file." object:nil]; goto clean_up_all; } int bytes_written = fwrite(buffer, 1, bytes_read, out_file); if (bytes_written != bytes_read) { [[NSNotificationCenter defaultCenter] postNotificationName:@"Unable to write to output file." object:nil]; goto clean_up_all; } [[NSNotificationCenter defaultCenter] postNotificationName:@"Copy block completed successfully." object:nil]; // clean up clean_up_all: free(buffer); clean_up_files: fclose(out_file); clean_up_in_file: fclose(in_file); end: return; }Please note that this is not a recommendation to always structure your error handling in this fashion using
goto
. This is simply one technique among many that you may encounter "in the wild" and which you may choose to use in the appropriate situation. When goto
is used carefully and sparingly, it can help make difficult code cleaner and easier to follow, but unrestrained use of goto
has the opposite effect. Whenever you're tempted to use goto
in your own code, you should stop and see if you can break the code down into smaller functions or methods. Very often, refactoring a long function or method by extracting chunks of code into smaller functions or methods will do far more for you than a goto
can.Next time, a summary of looping and a new topic: variables.
Friday, December 4, 2009
Tuesday, December 1, 2009
Objective-C Tuesdays: goto
Last time we looked at using the
A
The
Though mostly eschewed in favor of the
continue
statement to skip to the next iteration of a loop. This week, we will finish looking at loops with the most primitive looping statement of all: the goto
statement.A
goto
statement always references a label, which is simply an identifier followed by a colon (:). When the goto
statement is reached, execution jumps to the label and continues from that point. The label can be before or after the goto
statement.// goto and label examples start: // label named "start" // do some stuff if (...) { goto start; } // do more stuff if (...) { goto end; } // and more stuff end: // label named "end"Labels do nothing by themselves except mark places in code that you can jump to using
goto
.The
goto
statement has one big limitation: it only works within a single function. If you write something like this:// goto may only jump to labels within a function // THIS CODE DOESN'T COMPILE void function1(void) { label1: goto label2; } void function2(void) { label2: goto label1; }The compiler will produce error messages like label ‘label1’ used but not defined. Without this restriction,
goto
could be abused to create difficult to understand spaghetti code (ask any old time BASIC programmer about this). Because of this restriction, label names are local to the function that contains them, so you can use the same label name in different functions.Though mostly eschewed in favor of the
for
, for...in
, while
and do...while
loops, the goto
can be used to implement loops:int i = 0; startLoop: // label "startLoop" NSLog(@"%d", i); i++; if (i < 10) { goto startLoop; }This loop logs the numbers from 0 to 9. It's equivalent to this while loop:
int i = 0; while (i < 10) { NSLog(@"%d", i); i++; }Because the other looping statements are more compact and expressive, you will rarely see
goto
used to build loops.
Next time, we'll look at common uses for goto
.
Friday, November 27, 2009
iPhone Friday - November 27, 2009
Hello and Happy Gobble Gobble! I hope you all are recovering nicely from your tryptophan enduced food coma. Sorry for being late on this iPhone Friday as I too was feeling lethargic from a days worth of eating. So today I am posting the iPhone and iPod touch wallpapers - they are - sublime... Enjoy!
Tuesday, November 24, 2009
Objective-C Tuesdays: continue
See Also
Looping in Objective-C
Last week we looked at how to end a loop early using the Looping in Objective-C
break
keyword. Today we will look at a similar action: how to skip to the next iteration.Sometimes you need to process each item in a collection or sequence, but some of those items get full processing and some don't. For example, you may want to skip empty strings in a collection. Frequently you do this using an
if...else
statement:NSArray *collection = [NSArray arrayWithObjects: @"foo", @"", @"bar", @"baz", @"", nil]; int wordCount = 0; for (NSString *item in collection) { NSLog(@"found '%@'", item); if (item.length > 0) { wordCount++; } } NSLog(@"word count = %d", wordCount);This is generally a good approach, but sometimes you have complex nested logic:
NSArray *collection = [NSArray arrayWithObjects: @"foo", @"\n", @"bar", @"baz", @"", nil]; int wordCount = 0; for (NSString *item in collection) { NSLog(@"found '%@'", item); if (item.length > 0) { if ( ! [item isEqualToString:@"\n"]) { wordCount++; if (item.length < 4) { NSLog(@"short word"); } else { NSLog(@"long word"); } } } } NSLog(@"word count = %d", wordCount);The
continue
statement can help you simplify complicated cases like this by stopping the execution of the loop body for the current item and advancing to the next. Using continue
, we can rewrite the example like this:NSArray *collection = [NSArray arrayWithObjects: @"foo", @"\n", @"bar", @"baz", @"", nil]; int wordCount = 0; for (NSString *item in collection) { NSLog(@"found '%@'", item); if (item.length > 0) continue; if ([@item isEqualToString:"\n"]) continue; wordCount++; if (item.length < 4) { NSLog(@"short word"); } else { NSLog(@"long word"); } } NSLog(@"word count = %d", wordCount);Like
break
, a continue
statement only works on the innermost loop that encloses it:// outer loop for (int i = 0; i < 10; i++) { // loop A if (...) continue; // skips to next item in A // inner loop for (int j = 0; j < 10; j++) { // loop B if (...) continue; // skips to next item in B } if (...) continue; // skips to next item in A }The
continue
statement is most useful with a for
or for...in
loop, but can be used with a while
and do...while
loop with care. It's easy to create an infinite while
loop using continue
:NSArray *collection = [NSArray arrayWithObjects: @"foo", @"", @"bar", @"baz", @"", nil]; int wordCount = 0; int i = 0; while (i < collection.count) { NSString *item = [collection objectAtIndex:i]; NSLog(@"found '%@'", item); if (item.length > 0) { continue; // OOPS! forgot to increment i } wordCount++; i++; } NSLog(@"word count = %d", wordCount);This loop will reach the second item in the collection and get stuck there -- it never reaches the
i++
at the end of the loop body. The solution is simple:NSArray *collection = [NSArray arrayWithObjects: @"foo", @"", @"bar", @"baz", @"", nil]; int wordCount = 0; int i = 0; while (i < collection.count) { NSString *item = [collection objectAtIndex:i]; NSLog(@"found '%@'", item); if (item.length > 0) { i++;; // move to next item continue; } wordCount++; i++; } NSLog(@"word count = %d", wordCount);This is a consequence of the free-form nature of the
while
and do...while
loops. The compiler knows how to make a for
or for...in
loop advance to the next item, but the other loops leave that up to you; continue
acts more like a special goto
statement with while
and do...while
loops.Next time, we'll look at the mother of all loops, the
goto
statement.
Friday, November 20, 2009
Tuesday, November 17, 2009
Objective-C Tuesdays: break out of a loop
Last week we finished looking at the four looping statements in Objective-C: the
Sometimes you want to stop a loop prematurely. A common example of this is when you need to iterate over an unsorted collection or array looking for an item:
You can use a boolean flag variable to indicate when you're done:
You can use
Next week we will look at the other loop flow modifier,
for
loop, the Objective-C 2.0 for...in
loop, the while
loop and the do...while
loop. Today we'll look at how you break out of a loop early.Sometimes you want to stop a loop prematurely. A common example of this is when you need to iterate over an unsorted collection or array looking for an item:
NSArray *collection = [NSArray arrayWithObjects:@"foo", @"a", @"bar", @"baz", @"b", nil]; for (NSUInteger i = 0; i < collection.count; i++) { NSString *item = [collection objectAtIndex:i]; NSLog(@"Checking item '%@'", item); if (item.length == 1) { NSLog(@"Found single letter at index %u", i); /* no need to look at the rest -- we can stop now */ } }Once you find the item you're looking for, there's no need to finish the loop. In fact, if you search the whole collection, you will always find the last item that matches your criteria, which isn't always what you want.
You can use a boolean flag variable to indicate when you're done:
NSArray *collection = [NSArray arrayWithObjects:@"foo", @"a", @"bar", @"baz", @"b", nil]; BOOL foundFirst = NO; for (NSUInteger i = 0; i < collection.count && ! foundFirst; i++) { NSString *item = [collection objectAtIndex:i]; NSLog(@"Checking item '%@'", item); if (item.length == 1) { NSLog(@"Found first single letter at index %u", i); foundFirst = YES; } }This approach works, but is somewhat complicated and error-prone. A nicer way to exit a loop early is to use the
break
keyword. Using break
, the example becomes:NSArray *collection = [NSArray arrayWithObjects:@"foo", @"a", @"bar", @"baz", @"b", nil]; for (NSUInteger i = 0; i < collection.count; i++) { NSString *item = [collection objectAtIndex:i]; NSLog(@"Checking item '%@'", item); if (item.length == 1) { NSLog(@"Found first single letter at index %u", i); break; } }When the
break
statement is encountered, loop processing is stopped and execution resumes with the first statement after the loop; you can think of break
as a sort of return
statement for loops.You can use
break
to exit any of the loop statements. If we don't care about the index of the first item, we can simplify the example further by using the for...in
loop:NSArray *collection = [NSArray arrayWithObjects:@"foo", @"", @"bar", @"baz", @"", nil]; for (NSString *item in collection) { NSLog(@"Checking item '%@'", item); if (item.length == 1) { NSLog(@"Found first single letter"); break; } }The
break
statement only works on the innermost loop that encloses it:// outer loop for (int i = 0; i < 10; i++) { if (...) break; // skips to A // inner loop for (int j = 0; j < 10; j++) { if (...) break; // skips to B } // B } // AThe first
break
statement is inside the outer loop, and will skip to A. The second break
statement is inside the inner loop; it skips to B, ending the inner loop but staying inside the outer loop.Next week we will look at the other loop flow modifier,
continue
statement.
Tuesday, November 10, 2009
Objective-C Tuesdays: the do...while loop
Last time we looked at the
Unlike the
The
The
while
loop. Today we'll examine it's sibling the do...while
loop.Unlike the
while
loop, the do...while
loop is guaranteed to execute the loop body at least once. The loop condition is checked at the end of each loop iteration.The
do...while
loop starts with the keyword do
followed by a single statement or block that makes up the body of the loop. The loop body is followed by the keyword while
and parentheses containing the condition with a semicolon at the end.The
do...while
loop is almost always written on three or more lines, and almost always with a block instead of a single statement./* do...while loop with a single statement */ do statement; while (condition); /* do...while loop with a block */ do { block; } while (condition);Initialization of the loop counter or other loop variables must be done before the
do...while
statement; this often means declaring and initializing a local variable:int i = 0; do { /* ... */ } while (i < 10);When using a loop counter, it's important to remember to advance the counter to the next value in the body of the loop. For instance, to log the numbers 0 through 9:
int i = 0; do { NSLog(@"%d", i); i++; /* advance the loop counter */ } while (i < 10);If you forget to advance the loop counter, you'll create an infinite loop.
int i = 0; /* warning, infinite loop, i is always 0 */ do { NSLog(@"%d", i); /* oops, forgot to increment i */ } while (i < 10);The key thing that differentiates the
do...while
loop from the while
loop is that it always executes the loop body at least once; the while
loop doesn't guarantee that. An example of this difference:
BOOL looping = NO; NSLog(@"before while loop:"); while (looping) { NSLog(@" executing the while loop"); } NSLog(@"after while loop:"); NSLog(@"before do...while loop:"); do { NSLog(@" executing the do...while loop"); } while (looping); NSLog(@"after do...while loop:");The output of these two loops looks like this:
before while loop: after while loop: before do...while loop: executing the do...while loop after do...while loop:Next week, we'll look at using
break
to break out of a loop.
Friday, November 6, 2009
Friday, October 30, 2009
Thursday, October 29, 2009
iPhone Tech Talk World Tour 2009
We're attending Apple's iPhone Tech Talk World Tour 2009 in Santa Clara today. I went to last year's event and I highly recommend it. It's open to registered Apple iPhone developers only, but it's free and you get free breakfast and lunch and a t-shirt. And the talks are great too :-).
Tuesday, October 27, 2009
Tales of App Store Failure
Sean Maher, the creator of the iPhone zombie game Dead Panic, shares his sales figures and writes about the difficulty of building a sustainable business in Tales of App Store Failure.
Objective-C Tuesdays: the while loop
After the standard C
The
The initialization of the loop counter or other loop variables must be done before the
for
loop and the Objective-C 2.0 for...in
loop, the while
loop is the most common. Unlike the full-featured for
loop and the specialized for...in
loop, the while
is simpler and more free-form.The
while
loop starts with the keyword while
followed by parentheses containing the condition. After the parentheses, a single statement or block makes up the body of the loop./* while loop with a single statement */ while (condition) statement; /* while loop with a block */ while (condition) { block; }Watch out for a hard to spot bug when the
while
loop is followed by an empty statement created by an extra semicolon:while (condition); /* <-- warning! empty statement! */ { /* this block is not part of the loop */ /* it's always executed exactly once */ }The condition in a
while
loop is evaluated before the body of the loop is executed, so you can create loops that execute zero or more times. If you want the body of the loop to execute one or more times, you can use a do...while
loop instead.The initialization of the loop counter or other loop variables must be done before the
while
loop statement; often this means declaring and initializing a local variable:int i = 0; while (i < 10)When using a loop counter, it is important to remember to advance the counter to the next value in the body of the loop. For instance, to log the numbers 0 through 9:
int i = 0; while (i < 10) { NSLog(@"%d", i); i++; /* advance the loop counter */ }If you forget to advance the loop counter, you will create an infinite loop.
int i = 0; /* warning, infinite loop, i is always 0 */ while (i < 10) { NSLog(@"%d", i); /* oops, forgot to increment i */ }The
while
loop is frequently used when iterating over a stream or sequence of unknown size where a loop counter is unnecessary. For instance, to iterate over a null-terminated string by incrementing the string pointer:char const *s = "foobar"; while (*s) { /* while current character isn't zero */ NSLog(@"%c", *s); /* log the current character */ s++; /* increment address in s to next character */ }Similarly, the idiomatic way to read characters from a standard C
FILE
is:FILE *file = /* open file for reading ... */; int ch; while ( (ch = fgetc(file)) != EOF) { NSLog(@"%c", ch); }The loop condition
( (ch = fgetc(file)) != EOF)
in this idiom does three things:fgetc(file)
gets the current character and advances to the next(ch = fgetc(file))
assigns the current character toch
(ch = ...) != EOF
checks that the value ofch
is notEOF
do...while
loop.
Friday, October 23, 2009
Wednesday, October 21, 2009
Dear Palm, it's just not working out.
Jamie Zawinski has recently been writing about his travails trying to publish some open source applications for the Palm Pre. As iPhone developers who have to deal with Apple's often opaque and sometimes arbitrary approval process, we certainly sympathize.
On Monday he publicly declared that he's giving up on the Pre and buying an iPhone. And his beef is not with Palm's app approval process, but with the Pre itself:
Read Dear Palm, it's just not working out.
On Monday he publicly declared that he's giving up on the Pre and buying an iPhone. And his beef is not with Palm's app approval process, but with the Pre itself:
Believe it or not, this actually has nothing to do with my utterly nightmarish experience of trying to get my applications into Palm's app catalog, and everything to do with the fact that the phone is just a constant pain to use.He goes on to praise the iPhone:
and even though I absolutely despise the iPhone's on-screen keyboard... at least now I have a phone whose software actually works.Jamie's post also inspired Steve Frank of Panic to write about his love-hate relationship with the iPhone.
Read Dear Palm, it's just not working out.
Tuesday, October 20, 2009
Objective-C Tuesdays: The for...in loop
We've looked at the standard
In Objective-C, collection classes such as
In older versions of Objective-C, looping over items in a collection is done using an NSEnumerator object in a
The
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.
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.Read more about The two App Stores.
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.
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 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
Infinite loop If you omit the initialization, condition and action expressions, you get an infinite loop:
Missing loop expression Sometimes, there's no need to initialize a variable before looping, so the initialization expression is omitted:
Nested loops When building or processing tables of information, put one
Parallel iteration You can use multiple loop counter variables by using the comma (
There's a gotcha with the initialization expression however: only one loop counter variable can be declared there. It seems logical to do this:
Next week, we'll look at the Objective-C 2.0
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.
Monday, October 12, 2009
Tearing down the App Store hype
Newsweek recently published an article entitled Striking It Rich: Is There An App For That?. While it's an interesting read, it's the typical post-hype tear-down article. Since the opening of the iTunes App Store, the press has relentlessly hyped the "get rich quick selling iPhone apps" story. Well, I guess the story has played out; now the tear-down begins.
It seems Newsweek has discovered that not everyone instantly strikes it rich. In fact, it takes most of us a lot of work, a bit of risk and more than a little perseverance to bootstrap a new business. And even successful iPhone developers in the hit-driven gaming segment are worried about how well their next game will sell. With a different tone, the article would actually be an interesting exposé on high tech entrepreneurship, but Newsweek writer Tony Dokoupil gives the piece an air of dejection and disillusionment.
David Barnard of App Cubby, who is featured in the article, wrote an interesting rebuttal (warning: contains a cute baby picture at the end).
iPhone developer Bjango also recently posted a rebuttal in their blog.
It seems Newsweek has discovered that not everyone instantly strikes it rich. In fact, it takes most of us a lot of work, a bit of risk and more than a little perseverance to bootstrap a new business. And even successful iPhone developers in the hit-driven gaming segment are worried about how well their next game will sell. With a different tone, the article would actually be an interesting exposé on high tech entrepreneurship, but Newsweek writer Tony Dokoupil gives the piece an air of dejection and disillusionment.
David Barnard of App Cubby, who is featured in the article, wrote an interesting rebuttal (warning: contains a cute baby picture at the end).
iPhone developer Bjango also recently posted a rebuttal in their blog.
Friday, October 9, 2009
Wednesday, October 7, 2009
Building iPhone Apps with HTML, CSS, and JavaScript
O'Reilly has published a pre-print HTML version of the book Building iPhone Apps with HTML, CSS, and JavaScript by Jonathan Stark.
Building iPhone Apps with HTML, CSS, and JavaScript covers web apps vs. native apps for iPhone, styling HTML for the iPhone, animation, client-side data storage and offline application caching.
This book looks like it's going to be a valuable resource for both iPhone SDK app creators and web developers who want to target iPhone users.
Building iPhone Apps with HTML, CSS, and JavaScript covers web apps vs. native apps for iPhone, styling HTML for the iPhone, animation, client-side data storage and offline application caching.
This book looks like it's going to be a valuable resource for both iPhone SDK app creators and web developers who want to target iPhone users.
Tuesday, October 6, 2009
Objective-C Tuesdays: The for loop
Welcome to the first episode of Objective-C Tuesdays. We'll be focusing on C and Objective-C basics. Today we will look at the standard C language
The
The
Initialization The initialization expression is where the starting value of the loop counter variable is set. The initialization expression is evaluated once before the
Condition The condition expression is evaluated before each iteration; the loop continues while the condition evaluates to
Action The action expression is evaluated at the end of each iteration, after the condition and the body of the loop are executed. The action is typically used to increment or decrement the loop counter, but can be used to perform any action that makes sense for your code. Most of the time, you simply want to increment the counter by one:
Example Putting this all together, here's some Objective-C code to count from 0 to 5 and back to zero:
Next week, we'll look at some of the crazy and complicated ways you can use the
for
loop.The
for
loop is the most flexible looping statement in C, and the most common. It groups all the important loop information together at the start of the loop, making it quick and easy to both read and write.The
for
loop statement starts with the keyword for
, followed by parentheses containing the loop definition. The loop definition contains three expressions separated by semicolons: initialization, condition and action. After the parentheses, a single statement or block makes up the body of the loop./* for loop with a single statement */ for (initialization; condition; action) statement; /* for loop with a block */ for (initialization; condition; action) { block; }Watch out for a hard to spot bug when the
for
loop is followed by an empty statement created by an extra semicolon:for (initialization; condition; action); /* <-- warning! empty statement! */ { /* this block is not part of the loop */ /* it's always executed exactly once */ }
Initialization The initialization expression is where the starting value of the loop counter variable is set. The initialization expression is evaluated once before the
for
loop begins executing. Loop counters are commonly integer types, but can be any type that makes sense in your code. In modern versions of C and Objective-C, the loop counter can be declared in the initialization section as well. The loop counter is typically given the name i
(or j
or k
in nested loops). In C99 and later, initialization looks like: for (int i = 0; condition; action)In older versions of C, the loop counter must be declared somewhere before the
for
loop: int i; /* ... */ for (i = 0; condition; action)
Condition The condition expression is evaluated before each iteration; the loop continues while the condition evaluates to
true
or non-zero and stops when the condition evaluates to false
or zero. The condition expression is often a "less than" (<
) or "less than or equal to" (<=
) expression: for (int i = 0; i < 10; action)or
for (int i = 1; i <= 10; action)but it can be any expression that makes sense in your code.
Action The action expression is evaluated at the end of each iteration, after the condition and the body of the loop are executed. The action is typically used to increment or decrement the loop counter, but can be used to perform any action that makes sense for your code. Most of the time, you simply want to increment the counter by one:
for (int i = 0; i < 10; i++)but other increments are easy to do:
for (int i = 0; i < 10; i += 2)
Example Putting this all together, here's some Objective-C code to count from 0 to 5 and back to zero:
for (int i = 0; i <= 5; i++) { NSLog(@"%i", i); } for (int i = 4; i >= 0; i--) { NSLog(@"%i", i); }The output looks like this:
0 1 2 3 4 5 4 3 2 1 0
Next week, we'll look at some of the crazy and complicated ways you can use the
for
loop.
Monday, October 5, 2009
Orchard's Craps now available in the iTunes App Store
Able Pear is very happy to announce that our latest application, Orchard's Craps, is now available in the iTunes App Store.
Orchard's Craps is an iPhone and iPod touch version of the classic casino dice game and is the first of in the Orchard's Casino series of games.
Orchard's Craps features include:
We hope you enjoy playing Orchard's Craps as much as we enjoyed creating it!
Click here to see our complete list of apps.
Orchard's Craps is an iPhone and iPod touch version of the classic casino dice game and is the first of in the Orchard's Casino series of games.
Orchard's Craps features include:
- Animated 3D dice with sound
- Real stickman calls for rolls
- Horn and Hard Ways bets
- Adjustable minimum bet, maximum bet and pass line odds
- Standard casino craps table rules
We hope you enjoy playing Orchard's Craps as much as we enjoyed creating it!
Click here to see our complete list of apps.
Friday, October 2, 2009
iPhone Friday - October 2, 2009
It's Friday, and with it comes new iPhone and iPod touch wallpapers. This week is the third installment of the Hubble Space Telescope set (links after images).
Hubble Space Telescope sets:
iPhone Friday, October 18, 2009 - HST Set 1
iPhone Friday, October 25, 2009 - HST Set 2
iPhone Friday, October 18, 2009 - HST Set 1
iPhone Friday, October 25, 2009 - HST Set 2
Subscribe to:
Posts (Atom)