July 2011

KJMenuTableViewController - iOS Menus Made Easy

I have a new open-source library on Github for use by iOS developers: KJMenuTableViewController.

KJMenuTableViewController is an Xcode project that contains set of classes that simplifies the
creation of "menus" in iOS applications using UITableViewController.

The UITableViewController class is a generic mechanism for presenting a scrollable list of
rows of items. It is powerful and extensible, but it can be a chore to present a simple
list of button-like objects that react when tapped. One must provide implementations of several
methods of the UITableViewDataSource and UITableViewDelegate classes, each of which will
probably have a case statement to handle each of the individual items. It's not difficult, but it is
tedious and error-prone.

The KJMenuTableViewController classes simplify this usage case. One simply defines a subclass of
KJMenuTableViewController and overrides the viewDidLoad method to create sections and row items.
KJMenuTableViewController implements the table view delegate and data source methods to
appropriately display the sections and rows, and will take action when a row is tapped.

The code to be executed when an item is tapped are written as a block.
When the block is invoked, a KJMenuItemInvocation structure is passed to it. This structure
contains pointers to the menu item, cell, and controller, so there is no reason for the block
to retain any of these objects itself. (Beware of retain cycles if the block does reference
the menu item, cell, or controller.)

Beware the Lure of the iOS UIWebView

Apple's iOS SDK provides a class, UIWebView, that provides a simple way to display HTML content in an iOS application. Many apps use UIWebView to display web pages, online help, and other formatted content.

For the basic purpose of displaying HTML content, it works pretty well. However, as it appears to just be a wrapper around WebKit, one might be tempted to use it to try to implement a full-fledged web browser embedded in an application. Don't do this! UIWebView has many limitations that make it unsuitable for this purpose:

  • Many commonly used JavaScript functions, such as alert() and window.open(), don't work at all or only work in limited ways in a UIWebView. So many of the web sites one would try to visit do not work in a UIWebView.
  • There are limited hooks for customizing the behavior. There are a few delegate methods that notify your app when the web view starts loading or finishes loading, but you can't detect many of the events you'd really want to detect.
  • UIWebView does not send the same browser identification info that Mobile Safari does, so some servers will treat it as an unknown browser and return limited content.

Of course, some intrepid developers have found ingenious ways to work around some of these limitations. If you really want to try it, or if you are curious about what kinds of hackery are needed to use UIWebView as a web browser, check out these links:

The lesson I learned (after several hours of banging my head against the wall) is to pass web URLs over to Safari, rather than trying to display them in a UIWebView within my app. It's just not the right tool for this job.

Update (2011/10/1): My original post included this bullet point:

  • You can't control authentication. UIWebView can open an HTTPS connection, but if the server-side certificate is self-signed, there is no way to get it to ignore the certificate, and so it just fails with an error message.

I've been informed that this is not entirely true. It is possible to somehow "preconnect" to the server with an NSConnection, deal with authentication, and then pass the credentials to the UIWebView. More information is available here: http://stackoverflow.com/questions/11573164/uiwebview-to-view-self-signe...