Today is the last day of a 5-day course on iPhone programming class led by Joe Conway from Big Nerd Ranch. During the course I've been taking notes on how development for the iPhone compares to development for Android. By the way, BNR also offers Android courses if you're interested.
Judging by all the traffic this week, this is a topic of great interest to readers. Be sure to check out my coverage of the previous days if you missed them, and please leave comments with your thoughts:
Yesterday we covered Core Graphics, View Transitions, Core Animation, and the use of the Camera and Accelerometer. Today's session will cover:
- Web Services
- Address Book
Ok, let's get started:
Next: Web Services, Address Book > Web Services
There are many definitions for what constitutes a web service, but essentially it's a way for your program to make requests to a program running on a remote machine (usually with the HTTP protocol) and get back results (usually in XML or JSON format). For example in Hello, Android I have a sample program that uses the Google Translation web service to translate text from one language to another. You type a phrase on the phone, select a target language, and the program queries the server, gets back the translation, and displays it on the screen.
You can do the same thing on the iPhone. In class we wrote an example that called a service on www.random.org that returns a random number. There are many ways to do it, but for this example we allocated a NSMutableURLRequest, filled it in with our arguments, and called NSURLConnection:sendSynchronousRequest to connect to the remote server and wait for results.
Asynchronous requests are also possible (and preferred). For those you create a delegate (listener) that will get called when the response is received.
For this particular service the result came back as XML which has to be parsed. We used the NSXMLParser class, which is a pull parser similar to SAX from the Java world. The iPhone doesn't have a DOM (tree) based parser.
On Android you use the standard Java URL connection routines to make web service requests. For asynchronous requests you have to spawn your own thread to handle the responses so that the UI doesn't block. Android comes with both an XML DOM parser and a JSON parser so interpreting results is easier. Neither platform has any special support for SOAP or WSDL so you have to roll your own (or use a 3rd party library) if you need that.
Applications on the iPhone can access your contacts list in one of two ways: the standard UI and a lower level read/write interface.
If all you need is to pop up a view asking the user to select a contact then it's very easy. Create an ABPeoplePickerNavigationController, set your class as a delegate, present it on the screen, and then you'll get a callback when the user selects something. The user interface cannot be customized.
In Android, you can do something similar by firing off a PICK intent with the right URL and content type. Normally the built-in Contacts application would handle the requests and return the results to you, but you can also write your own app that handles it instead.
If you need a low level interface to the address book database, a special C-language interface is available on the iPhone. Access is direct and unprotected, so a malicious app could read all your contacts and do something with them, even shuffle them around or delete them. Hopefully such a program would never make it through the App Store vetting process.
In Android, Contacts can be accessed through the standard Content Providers API. A Content Provider lets you share information (in this case, names and addresses) between two Android programs. The provider and the client that consumes it are running at the same time. The interface is similar to SQL, and data is returned in a Cursor object. From that you can read columns (name, date, etc.) and advance to the next row. You can submit modification requests. All access is through the Content Providers API and is tightly controlled. To access Contacts, for example, you have to ask for the READ_CONTENTS permission in your manifest. When somebody installs your application, the Android installer lists all the permissions you're requesting and asks the user if they really want to allow that.
Next: Preferences, Networking > Preferences
One thing that threw me right away is that the iPhone API uses the term "Defaults" to refer to application settings or preferences. To me, default means a value you use if the user didn't specify a setting. The iPhone API calls those "Factory defaults". Now that that's out of the way...
The iPhone has a built in program, ironically called "Settings", which the user can invoke to change any system or applications preferences. To get listed on this screen, you create an XML file named Root.plist which contains a PreferenceSpecifiers tag with an array of all your, um, settings. The Settings app understands certain preference types in there, such as PSToggleSwitchSpecifier for a yes/no button, and will create a user interface screen listing all the things the user can set.
In your iPhone program when you want to read the value of a preference you use the NSUserDefaults:standardUserDefaults method to get a pointer to the preferences object and then call methods such as boolForKey or stringForKey to read specific values. The key is just a string you make up. There is some extra complexitity involved in figuring out this is the first time your app has run and initializing the factory defaults. In the class example we opened and read the Root.plist file so we didn't have to specify the factory default values twice.
Android preferences are also defined in an XML file (res/xml/settings.xml), although like the iPhone you can define them in code if you really want to. Android will create the user interface for the preferences screen automatically, but it does this at your request *inside your program*. On Android there is no centralized preferences application shared by all programs. Contrast this with the iPhone where there is no way to show your preferences screen from within your program (it *only* shows in the system's Settings app).
On the iPhone, some localization is possible by changing the Root.strings file, but you can only localize the titles (not the values). Hopefully a future update from Apple will fix that. On Android you can localize both the titles and values using the strings.xml resource file.
There's not much to say about networking other than it's there and it works pretty much the way you would expect. The iPhone has one extra that Android doesn't have: finding servers with Bonjour.
A Bonjour server (also called Rendezvous or ZeroConf) uses a feature of DNS to allow a client to discover the server without knowing its IP address. This is a pretty cool feature, and it's been ported to non-Apple systems too. To access a Bonjour server from an iPhone app you allocate an NSNetServiceBrowser object, set a delegate for callbacks, and call its searchForServicesOfType method. The system will send you search results, and then you can use conventional methods to connect to those servers. You might be able to use a 3rd party Bonjour library for Android but it's not built into the system.
Next: Instruments, Conclusion > Instruments
Oh no, your iPhone app is leaking memory like a sieve. Who you gonna call? Leak Busters! Or more accurately, you run your program from Xcode with Leak instrumentation turned on. It works best with Objective-C objects that are leaked because it can identify those by name. Click on a leaked object to see a traceback of where it was allocated, and click on the traceback to open the source code to the right line.
Since the iPhone has no garbage collection, the Leak tool will be very handy in recovering all your memory and improving stability. Xcode also has intruments for system resources, CPU sampling (profiling), Core Graphics, OpenGL (framerates), and more. Android provides some of these but doesn't match what you can get for the iPhone.
Conclusion, Day 5
The APIs to access web services are a little primitive on both the iPhone and gPhone but it's functional. Just keep in mind that connectivity to a mobile device is often spotty. It's important that you handle errors gracefully, provide a way to cancel long operations, and never block the user interface.
Preferences are handled quite differently on the two systems. On the iPhone they're controlled centrally, and on Android each application handles its own. I'm not sure which approach is better, although I do find it handy to change my options while a program is running. To do that on the iPhone would require you to implement a special UI. If you're doing something like a game that is fully custom anyway, then this isn't a big deal, but it's something to keep in mind.
Several people have asked me, "Which system should I program for?" The answer depends on what you're trying to do. The iPhone shines in areas like music and UI consistency, while Android's strengths are its openess, customizability, and multi-vendor support. Both systems will be with us for many years to come, so perhaps the answer is "both".
Well, that wraps it up for the iPhone class. I had a lot of fun, and learned a lot. I hope you've found these notes helpful. Be sure to check out the other articles in this series: