Yesterday we learned about creating a simple iPhone application, using Interface Builder, handling user interface events, and Location based services with the CLLocationManager class. Today's agenda includes:
- View Controllers
- Table Views
Here are some impressions I recorded during each session, followed by a wrap-up of my conclusions for the day:
Next: Localization > Localization
Localization is the process of adapting a program to different languages. When I write a program I first write it using English messages, and then someone else can translate those messages to French, German, and so forth. To make things easier for them we collect all the messages in one place, and arrange it so the translator does not have to touch the code in order to change the text.
On the iPhone, some strings are kept in the Localizable.strings file. In the code, you use the NSLocalizedString() function, passing it a key string and a comment for the translator. Then you run the genstrings utility to create Localizable.strings, then in Xcode you add that file to your project, right click on it, select Get Info > General > Add Localization. In Xcode it now looks like you have two files but in reality you have two directories, one for English and one for, say, French. Localizable.strings is somewhat similar to a Java resource bundle, though the format is a little different.
Unfortunately some strings are not kept in Localizable.strings. In particular, any labels or other text that you enter in the Interface Builder don't go there. So, you have to separately localize the Project.xib file for each language as well. That's right, you have to have a different user interface for each language. If you want to go back later and, say, add a new button, you have to add it to every localized version of the interface file.
Contrast this to Android, which concentrates all human readable text in the strings.xml file. Strings in code and strings in the user interface (layout XML files) both refer back to that bundle. In addition, Android saves space by using integers instead of text strings as the resource key. Let's say you define a string called "perform_action_text" and an English translation of of "Perform the action". Once you add that to strings.xml, the Android Eclipse plug-in will add an integer key called R.strings.perform_action_text which you use in your Java code. You can also refer to "@strings/perform_action_text" in your XML which is compiled by the Android resource compiler into a machine readable format. This has two advantages: first an integer takes less space than a string key, and second, the compiler can do static type checking and code completion for you because the keys are constants and not random strings.
Next: View Controllers, Table Views > View Controllers
On the iPhone, UIViewControllers are the cornerstone of the user interface. Each app can have several of these, each of which manages a single full-screen UIView. UINavigationController is a view controller that controls a stack of other view controllers. This is the class that handles the "back" button at the top of many screens. UITabBarController is another view controller that allows switching between a list of other view controllers. This is the class that handles the (usually) black tab bar at the bottom of some apps.
Getting all this wired up in Interface Builder is no small feat for the newcomer. For each view controller you need a .xib file, and you link them together through code and properties in the Inspect view. When you have a .xib file you can have Xcode auto-generate the class and header file for you, so some duplication there is avoided.
Android's equivalent to the UITabBarController is the TabWidget, except it displays the tabs at the top instead of the bottom of the window. Instead of UINavigationController, Android uses Activities and a physical Back button to navigate between screens. The iPhone has some limited ability to recover memory in low memory situations by calling a method on views that aren't currently visible and then releasing them. Android goes a bit beyond that with an extensive set of life cycle methods and the ability to delete an entire process and restore it later if needed. The Android model is more complicated because it has to handle both foreground and background programs and a stack of applications that works much like browser pages that can be navigated with the Back button.
Tables on the iPhone are pretty cool. Although they don't have the flexibility of data-bound controls using Adapters on Android, they do have a lot of built-in functionality that you get for free. In particular, iPhone tables have an editing mode that draws standard delete and move icons in the table (squeezing the content that's there). You have to handle changing the model (data) yourself, but this makes the user interface consistent from one app to the next.
Next: WebKit, Sound, Conclusion > WebKit
Due to its musical heritage, the iPhone is considerably more adept at playing and recording audio than Android. In version 2.1 of the iPhone SDK, however, the programming interface is very low level. It reminds me of Microsoft's DirectX in that you allocate and fill buffers and get callbacks when buffers are drained (or filled if recording). For these interfaces you actually program in C instead of Objective-C because it uses older Core Foundation classes brought over from MacOS X. In version 2.2 Apple is introducing friendlier classes for playing audio and video, so that will be a welcome change.
Android can play sound and video with its MediaPlayer class, but there are some limitations. I cover some of these in my book, but basically it's not functional enough for some applications like overlapping sound effects in games. There is a SoundPool class you can use, but it's prone to crashing if you're not careful with it (for example if you tell it you're going to have 3 simultaneous sounds and you accidentally give it 4). Hopefully future versions of Android will address these shortcomings. The iPhone 2.2 API looks similar to the Android MediaPlayer API in terms of simplicity and ease-of-use so the problem is not so much with the interface but with the implementation in Android 1.0.
Conclusion, Day 2
Localizing iPhone apps for non-English markets seems to be one of the weak points in the platform. If you have strings in your user interface, you're in for some extra work when you have to keep several language-specific versions of the interface up to date as your program evolves. The instructor advised us to forget about localization until late in the development cycle.
On the other hand, as a commenter pointed out, Android localization support is somewhat theoretical as of 1.0 because a) there is no global language setting, and b) localized versions of the OS itself are not yet available. Google promises that the German version will be out this year and several other languages will be available in 1Q2009. But as of now, Android is behind in practical implementation terms for localization but ahead in API hooks available to programmers.
The design of views and navigation is starkly different between the two platforms, as they both take different approaches to handling the small screen and memory constraints. The iPhone does everything with no physical keys, while Android relies on a Back button, which affects some of the UI decisions. Internally, Android's job is a little more difficult because they have to handle background processes.