Thursday, October 14, 2010

A Fix for a Seemingly Random iOS App Network Failure

Or How do I display the WiFi connection dialog?

If you're writing an iPhone, iPod touch or iPad app that uses the network, it's important that you set the UIRequiresPersistentWiFi key in your Info.plist file, otherwise your app may occasionally fail to connect to any network resources it requires. You will never see this failure in the simulator, or on an iPhone that has cellular service activated. Let me explain.

In order to conserve battery, iOS devices disconnect any active Wi-Fi connection after 30 minutes if the device is idle or asleep, unless the currently running app has the UIRequiresPersistentWiFi key set. If an app does not have this key set, the system doesn't automatically try to reestablish a Wi-Fi connection, even when your app tries to connect to the network.

The simulator uses your Mac's network connection—it never prompts you to connect via Wi-Fi. An iPhone with active cellular service will automatically use the cellular data network if the Wi-Fi transmitter is asleep.

You can test this on an iPod touch or Wi-Fi iPad, or on an iPhone in Airplane Mode with Wi-Fi turned on. In the Settings app, tell the device to forget any current Wi-Fi network; this will disconnect the Wi-Fi transmitter and turn it off. Then run your app. If you don't have UIRequiresPersistentWiFi set, the device won't prompt you to establish a Wi-Fi connection and any attempts your app makes to connect will fail.

When your app has UIRequiresPersistentWiFi set, the device will automatically connect to known Wi-Fi networks or pop up the standard Wi-Fi connection dialog if no known Wi-Fi network is available, and will maintain the connection while your app is active. This is especially critical for users of Wi-Fi only devices. If users complain that they sometimes have to open Safari or another app in order to get the network to connect, you forgot to set UIRequiresPersistentWiFi in your Info.plist.

One little annoyance: in Xcode (currently at version 3.2.4), the Info.plist editor doesn't include UIRequiresPersistentWiFi in the drop-down list of keys. In order to add it, create a new row and just type UIRequiresPersistentWiFi into the Key field, then right-click on the Value field and choose Value Type -> Boolean from the menu. Alternately, in the Groups & Files tree, right click on the Info.plist file and select Open As -> Source Code File from the menu. Then you can simply add
  <key>UIRequiresPersistentWiFi</key>
  <true/>
to the <dict> tag in the <plist> tag.

Wednesday, October 13, 2010

Apple to Announce OS X 10.7 Lion

Apple sent out invitations to the press today for a Mac related event on October 20th. With a lion peeking out of the invitation, there's no doubt that the next version of OS X will be announced and be code-named "Lion".

Let the speculation begin on what other cool new things will be announced.

Monday, October 11, 2010

12 Great Tips for iPhone Web Development

I just ran across this great article on SitePoint by Stoyan Stefanov, a Yahoo engineer and author of Object-Oriented JavaScript. It's called iPhone Development: 12 Tips To Get You Started. Since SitePoint is all about web development, they left the Web out of iPhone Development, but it's a great article nonetheless.

Stoyan covers just about everything you might want to do with HTML, CSS and JavaScript to customize your site for the small screen:
  1. use the iPhone Simulator and SDK documentation
  2. add the correct CSS @media declaration
  3. set the viewport meta tag
  4. handle orientation changes with JavaScript
  5. set orientation specific styles
  6. hide the Mobile Safari toolbar
  7. use CSS to create rounded corners
  8. handle touch events
  9. handle gestures
  10. add links to make voice calls and send text messages
  11. add an app icon
  12. debug using JavaScript and Xcode
Unfortunately he doesn't cover anything specific to the iPad—the article is actually from April 2009. Still, whether you want to optimize your site for iPhone and iPod touch users or need to show some custom web content in a UIWebView in your native app, just about everything you need to know is summarized right here. Check it out!

Friday, October 8, 2010

iPad Friday: October 8, 2010

Hello and happy Friday.  Today's collection of iPad wallpapers are from a experimental project and soon to be iPhone app.  These wallpapers make great backgrounds so you can easily see your icons and labels.  Cheers!

(click an image for the full-size wallpaper)












iPhone Friday: October 8, 2010

Hello and happy Friday.  Today's collection of iPhone wallpapers are from a experimental project and soon to be iPhone app.  These wallpapers make great backgrounds so you can easily see your icons and labels.  Cheers!

(click an image for the full-size wallpaper)












Thursday, October 7, 2010

Xcode Analyzer Error: "Analyzer skipped this file due to parse errors"

Apple integrated the Clang Static Analyzer into Xcode a while back. It's a part of the LLVM project and it uses the clang C/C++/Objective-C compiler front-end to the LLVM compiler to perform static analysis. The static analyzer (or "clang checker") is really useful for finding common retain/release errors in Objective-C code. You run the analyzer by building your project using the Build and Analyze item under the Build menu.

When I recently went to run the static analyzer on one of my projects using the recently released iOS 4.1 SDK, I got a series of the following types of errors:
Analyzer skipped this file due to parse errors

 '/var/folders/p9/p9X0YndXGHyxgsdRDDYre++++TI/-Caches-/com.apple.Xcode.501/SharedPrecompiledHeaders/PrecompiledHeaders-cbytywsinixhviaxvbooriusnxyo/PrecompiledHeaders.pch' file not found
I found the following workaround for the problem in the Apple developer forums (registration required).

On the Project menu, select Edit Active Target "MyProject" to bring up the Target Info dialog. Edit the Other C Flags setting and add -D__IPHONE_OS_VERSION_MIN_REQUIRED=030000, where 030000 corresponds to the iOS Deployment Target setting:
  • 3.0 -> 030000
  • 3.1 -> 030100
  • 3.2 -> 030200
  • 4.0 -> 040000
  • 4.1 -> 040100
Then the analyzer should be able to run successfully.

Wednesday, October 6, 2010

iOS SDK 4.1 Breaks Unit Tests

I ran into this problem a couple of weeks ago, but didn't get around to blogging about it until today. If you use the OCUnit test framework that's part of Xcode to write unit tests, upgrading to iOS SDK 4.1 will give you a rude surprise:

Run unit tests for architecture 'i386' (GC OFF) did not finish

An internal error occurred when handling command output: -[XCBuildLogCommandInvocationSection testName]: unrecognized selector sent to instance 0x2010cff80

An internal error occurred when handling command output: -[XCBuildLogCommandInvocationSection setTestsPassedString:]: unrecognized selector sent to instance 0x2010cff80

An internal error occurred when handling command output: -[XCBuildLogCommandInvocationSectionRecorder endMarker]: unrecognized selector sent to instance 0x2009b8580

It seems there's a mismatch between Xcode and OCUnit in the 4.1 SDK release. At first I wasn't able to find a workaround. I was going to install iOS 4.2 SDK beta 1 anyway, so I went ahead and did that and found that the problem had been fixed. The beta SDK has been working fine for me (though you should still use the 4.1 release SDK if you're building for submission to the app store).

Checking back on this problem, there are now a couple of workarounds. Apple posted some Objective-C code in their developer forums that monkey patches the problem. And Andy W posted a simple workaround on Stack Overflow.

This isn't the first time that Apple has broken their officially supported unit testing framework with an update to Xcode. It's kinda ironic, but I guess they don't have good test coverage of their test framework.

Tuesday, October 5, 2010

Objective-C Tuesdays: replacing in strings

Welcome back to Objective-C Tuesdays! Today we follow closely on last week's topic of searching in strings with it's sibling, replacing in strings.

It's a nightmare in C
In our series on strings in Objective-C, we've usually started by looking at C strings then moved on to NSStrings. Today is no different. In most cases, using NSString is easier than doing the equivalent operation on C strings. When it comes to replacing characters in a string, using NSString is significantly easier and safer. The standard C library doesn't provide much support for doing common string replacement operations, so you have to implement them yourself. Because of all the manual memory management required when working with C strings, this code is very error prone -- writing off the end of a buffer and forgetting to add the null terminator are two very common types of errors you have to watch out for when working with C strings.

Replacing a character
The only replacement operation that's fairly straightforward on C strings is replacing a single character with another character. Since C strings are just pointers to arrays of chars, you simply calculate the pointer to the char you want to change, dereference the pointer and assign the new char value.

There are two variations of this. The first one uses array notation and the second pointer operations. In both examples below, we use the strdup() function to make a copy of our original C string. The strdup() function isn't part of the C standard library, but most systems have one available (possibly named _strdup()) and it's easy to write one if it's missing on your system (it's available on iOS). You own the string returned by strdup() and are responsible for calling free() when you're done with it.

Here's how you change a character in a C string by treating it as an array of chars:
char const *source = "foobar";

char *copy = strdup(source); // make a non-const copy of source

copy[3] = 'B';               // change char at index 3

NSLog(@"copy = %@", copy);
// prints "copy = fooBar"

free(copy);                  // free copy when done
The alternative way uses pointer arithmetic:
char const *source = "foobar";

char *copy = strdup(source); // make a non-const copy of source

char *c3 = copy + 3;         // get pointer to char at index 3

*c3 = 'B';                   // change char at address of c3

NSLog(@"copy = %@", copy);
// prints "copy = fooBar"

free(copy);                  // free copy when done
As far as the compiler is concerned, this is basically the same code so use whichever method makes the most sense. If you know the index of the char you want to change, use array notation. If you already have a pointer to the char, perhaps from calling strchr(), use the pointer directly.

Replacing a substring
Replacing a substring of a C string is harder. In the case where the original and the replacement have the same number of chars, you can call strncpy() to copy over the characters.
// replacing a substring of equal length
char const *source = "foobar";

char *copy = strdup(source); // make a non-const copy of source

char *c2 = copy + 2;         // get pointer to char at index 2

strncpy(c2, "OBA", 3);       // copy 3 chars

NSLog(@"copy = %s", copy);
// prints "copy = foOBAr"

free(copy);                  // free copy when done
Replacing a substring with a different sized one is even more complex. There are three special cases that need to be handled: the substring to replace is at the start of the original, in the middle, or at the end. When the replacement substring is smaller than the original, there are some short cuts you can take to make the code a little simpler, but we'll only show the general case.

We'll look at the second case, replacing a substring in the middle of the original. With a little extra logic, this code can be adapted to handle all three of our cases.
char const *source = "The rain in Spain";
char const *original = "rain";     // substring to find
char const *replacement = "plane"; // substring to replace

// calculate the required buffer size
// including space for the null terminator
size_t size = strlen(source) - strlen(original) 
            + strlen(replacement) + sizeof(char);

// allocate buffer
char *buffer = calloc(size, sizeof(char));
if ( ! buffer) {
  // handle allocation failure
}

// find original substring in source and
// calculate the length of the unchanged prefix
char *originalInSource = strstr(source, original);
size_t prefixLength = originalInSource - source;

// copy prefix "The " into buffer
strncpy(buffer, source, prefixLength);

// calculate where the replacement substring goes in the buffer
char *replacementInBuffer = buffer + prefixLength;

// copy replacement "plane" into buffer
strcpy(replacementInBuffer, replacement);

// find position of unchanged suffix in source and
// calculate where it goes in the buffer
char const *suffixInSource = originalInSource + strlen(original);
char *suffixInBuffer = replacementInBuffer + strlen(replacement);

// copy suffix " in Spain" into buffer
strcpy(suffixInBuffer, suffixInSource);

NSLog(@"buffer = %s", buffer);
// prints "buffer = The plane in Spain"

free(buffer); // free buffer when done
I won't even waste your time explaining this in detail. No one programming in a modern computer language should have to write this code! It's extremely error prone and is one of the main causes of security vulnerabilities. If you find yourself doing this, stop immediately and seek out one of the many managed string libraries for C that are available. If you're writing code for iOS, you should be using NSString to do this.

Replacing using NSString
The NSString class has a number of useful methods for replacing characters and substrings in an NSString. Because NSString is immutable, these methods all return a new NSString instance containing the replacements, leaving the source NSString unchanged.

When you know the exact area of the string you want to replace, you can use the -stringByReplacingCharactersInRange:withString: method with an NSRange structure, which has fields for location (the zero-based index to start at) and length (the number of characters in the source string to replace). Because NSString does all the memory management for you and returns a new autoreleased NSString, it's child's play compared to doing this with C strings.
// replace a range in an NSString
NSString *source = @"The rain in Spain";
NSRange range;

range.location = 4; // starting index in source
range.length = 3;   // number of characters to replace in source

NSString *copy = [source stringByReplacingCharactersInRange:range 
                                                 withString:@"trai"];

NSLog(@"copy = %@", copy);
// prints "copy = The train in Spain"

// no need to release anything
// copy is autoreleased
This is a definite improvement over working with C strings. You might actually do this in real code without tearing your hair out or causing a buffer overrun bug. We can make this code even more compact by using the NSMakeRange() function to create the NSRange structure.
// replace a range in an NSString
NSString *source = @"The rain in Spain";

// create range in line
NSString *copy = [source stringByReplacingCharactersInRange:NSMakeRange(4, 3)
                                                 withString:@"trai"];

NSLog(@"copy = %@", copy);
// prints "copy = The train in Spain"

// no need to release anything
// copy is autoreleased
If you don't know ahead of time what part of the string you want to replace, you can do a find and replace in one method. The -stringByReplacingOccurrencesOfString:withString: method will find all occurrences of one NSString in another and replace them, returning a new autoreleased NSString.
// find and replace one substring with another
NSString *source = @"The rain in Spain";

NSString *copy = [source stringByReplacingOccurrencesOfString:@"ain"
                                                   withString:@"oof"];

NSLog(@"copy = %@", copy);
// prints "copy = The roof in Spoof"
There is another variation of this method that gives you more control over how substrings are found and replaced. The -stringByReplacingOccurrencesOfString:withString:options:range: method allows you to specify a mask containing one or more options and an NSRange structure allowing you to restrict the operation to a section of the string. The most common option is NSCaseInsensitiveSearch, which matches the substring without regard to case.
// case insensitive replace
NSString *source = @"<BR>The rain<BR>in Spain";

NSString *copy = [source stringByReplacingOccurrencesOfString:@"<br>"
                                                   withString:@"<p>"
                                                      options:NSCaseInsensitiveSearch
                                                        range:NSMakeRange(0, [source length])];

NSLog(@"copy = %@", copy);
// prints "copy = "<p>The rain<p>in Spain"
Another handy search option is NSAnchoredSearch, which searches only at the start of the source string. Notice that you use the bitwise or (|) operator to combine multiple options together.
// anchored, case insensitive replace
NSString *source = @"<BR>The rain<BR>in Spain";

NSString *copy = [source stringByReplacingOccurrencesOfString:@"<br>"
                                                   withString:@"<p>"
                                                      options:NSAnchoredSearch | NSCaseInsensitiveSearch
                                                        range:NSMakeRange(0, [source length])];

NSLog(@"copy = %@", copy);
// prints "copy = "<p>The rain<BR>in Spain"
You can combine the NSBackwardsSearch with NSAnchoredSearch to only replace the substring if it occurs at the end of the source instead of at the beginning.

Replacing in NSMutableString
If you're working with an NSMutableString, you can still call any of the -stringByReplacing... methods to produce a new NSString, but you have the option of making the replacements in the NSMutableString directly. The method -replaceCharactersInRange:withString: is very similar to the -stringByReplacingCharactersInRange:withString method:
// replace a range in an NSMutableString
NSMutableString *source = [NSMutableString stringWithString:@"The rain in Spain"];

[source replaceCharactersInRange:NSMakeRange(4, 3)
                      withString:@"trai"];

NSLog(@"source = %@", source);
// prints "source = The train in Spain"
The method -replaceOccurrencesOfString:withString:options:range: works similarly.

In most cases, there's not much of an advantage to replacing in place in an NSMutableString versus creating a new NSString containing the replacement. Use whichever operation is most convenient. If you need to make many replacements on a very long string, there may be an advantage to replacing in place rather than creating many large temporary NSString instances that live in the autorelease pool.

So far, the searching and replacing methods we've seen have done only simple string matching. Next week, we'll look at more powerful string matching using regular expressions.

Monday, October 4, 2010

iPhone Code to Learn From

Programmers learn in different ways. Some need to read a step-by-step "how to" guide, others get by fine just using the official documentation and header files. Some are more comfortable attending a workshop or watching a video, others prefer to just dive in and write code.

Reading other programmers' code is another great way to learn about developing in a particular language or framework. A lot of programmers find reading strange code to be difficult, but it's a skill that I think is really important and I encourage every programmer to become comfortable with.

The folks at Web Resources Depot recently published 20+ Open Source iPhone Applications To Learn From which links to a bunch of open source iPhone apps that run the gamut from the official WordPress app to small utilities and games. If you learn best by reading code, or you want to improve your code reading skills, check it out!

Friday, October 1, 2010

iPad Friday: October 1, 2010

Hello and happy Friday.  Today's collection of iPad wallpapers continue our look at photos from around the neighborhood.  Cheers!

(click an image for the full-size wallpaper)






iPhone Friday: October 1, 2010

Hello and happy Friday.  Today's collection of iPhone wallpapers continue our look at photos from around the neighborhood.  Cheers!

(click an image for the full-size wallpaper)