Friday, July 1, 2011

Networking Library for iPhone and iPad

I've added a very useful and complete networking library to my open source GitHub repo. After you clone the repo, open the ikhoyo-public workspace in the workspaces directory, and then look in the ikhoyo-net project.

There is also some example code in the ikhoyo-top project. The sample retrieves some data from Socrata using the networking library. The library is called IkhoyoURLManager, and the Socrata library that wraps it is called IkhoyoSocrata, in the ikhoyo-socrata project.

Socrata has lot's of cool data and a very easy to use REST API. All open. You can also see a full example using all these technologies on Mobile Orchard. The post was authored by me and is called Using SQLite with iOS. The example gets some Socrata data and builds a database table using SQLite.

SQLite on the iPhone and iPad

I'm a guest author at Mobile Orchard. You can see my two posts about using SQLite on the iPhone and iPad:

1. Compiling Your Own Version of SQLite for iOS
2. Using SQLite with iOS

The posts describe using SQLite in great detail. You can find the accompanying code on my GitHub repo.

Saturday, May 28, 2011

Local Web Views for the iPad and iPhone

Sometimes we need to display complex information in iPhone or iPad applications. The UIWebView is a very handy for doing this. But how do we get dynamic or live data into our UIWebViews? Wouldn't it be nice to have the ability to make a full fledged web application that runs locally on the device?

This post shows you how to do this. The Ikhoyo Web View is a set of classes that make it easy to construct complex web applications that run on the local device. The web views can use live real time data from your application since templating is used to generate the final pages that are displayed in your view.

Ikhoyo web views are a combination of the Mustache templating language to generate xml or html, and Extensible Style Sheets (xsl) to generate the final page. Using xsl is not required, but as you'll see, it's very useful for generating complex html pages.

If you haven't already, go to GitHub and clone our repository. If you're using Xcode 4, go to the workspaces directory and open the ikhoyo-public workspace.

First, let's look at the structure of an Ikhoyo web view. In the ikhoyo-top project, you'll see a directory called xcode-resources/webviews. This contains the web views that we are displaying for this app. Currently, there are two of them, home and sample-web-view. home is what you see when you start ikhoyo-top, and sample-web-view is a detail view that you can select from the master table view on the left.

Look in sample-web-view. There are two files, index.xml and sample.xsl. To start an Ikhoyo web view in your code, you call the start method on IkhoyoWebViewController and pass in the base directory (xcode-resources/webviews/sample-web-view in this case). The start method looks for index.xml and runs it through Mustache with a context that you supply. The context contains any data the Mustache template needs to generate the xml file.

The Mustache template generates an xml file, which is then displayed in the UIWebView. The xml file contains a reference to sample.xsl, telling UIWebView to use that stylesheet to format the html in the web view. The style sheet processing is done inside UIWebView, we don't have to write code to do the transformation.

The style sheet processing is not required, and you can have the Mustache templates generate html directly. We prefer using xsl for anything even slightly complicated because the processing logic in xsl is very powerful, much more powerful than Mustache templates. It also insulates your code from changes. For instance, if you decide at a later date to get the data remotely, then you can use the same style sheet to display the data in the web view.

Let's look a little closer at SampleWebView. Select SampleWebView.xib. Open up the Navigation Controller in the tree and look at the Ikhoyo Web View Controller. This is where we wire up the UIWebView to the IkhoyoWebViewController. You must connect the webView outlet from IkhoyoWebViewController to the web view used to display the generated pages. In this case, the UIWebView is the same as the main view of the controller. You must also connect the delegate outlet on the UIWebView to the IkhoyoWebViewController. You can verify these are connected properly by viewing the connections in the Connections inspector for each object.

Also notice that we include the SampleWebViewContext in the xib file. It's not a UI object, but it's needed by the IkhoyoWebViewController. So why not let Interface Builder instantiate it and wire it up for us instead of doing it manually?

We'll drill down into the workings of the IkhoyoWebViewController later. For now, note that the only thing you need to do to get an IkhoyoWebViewController in your own apps is the following:

  • Make a directory in your bundle to hold the Ikhoyo Web view xml and/or xsl files. We hang our web views off of the xcode-resources/webviews directory.
  • Make a subclass of IkhoyoWebViewContext to hold any local data that your web view displays. We'll show you how this works later.
  • Wire up an IkhoyoWebViewController to a UIWebView with Interface Builder. We showed you how to do this above.
  • Call the start method on the IkhoyoWebViewController to start it up.

Most of the coding for Ikhoyo Web Views is either making the Mustache templates (which are usually quite simple), or the xsl style sheets (which can be quite complex). In other words, the only Objective C coding that you need to write is for the IkhoyoWebViewContext, which supplies the local data to the templates.

Let's switch back to some internals and see how the IkhoyoWebViewController does it's thing, then we'll delve into details of Mustache templates and xsl.

Click on IkkhoyWebViewController.m in the ikhoyo-ui project. Look at the start method. start expects the base directory of the web view. It looks for index.xml in the base directory and sends it through Mustache with the supplied context. The code for this is:
NSString* template = [NSString stringWithContentsOfFile:path 
  usedEncoding:&enc error:&error];
NSString* result = [GRMustacheTemplate renderObject:self.context 
  fromString:template error:&error];
The result is a string of xml which is displayed in the UIWebView with:
[self.webView loadData:data MIMEType:mime textEncodingName:@"utf-8" 
  baseURL:self.baseUrl];
For xml, the MIMEType must be 'text/xml', or the data won't be interpreted as xml, and any xsl processing won't occur.

Now let's switch back to the Mustache template, xsl style sheet, and IkhoyoWebViewContext. Look in xcode-resources/webviews/sample-web-view/index.xml. This is the Mustache template. You can read up on the details of Mustache templates here. All we're really doing is extracting some of the data from the context and inserting it into our xml file. The Objective C Mustache processor (which is included in ikhoyo-ui) uses key-value coding to find the things it needs in the context. For this example, we added a list of Items in the context (the listOfItems field). Mustache takes this list and inserts it into index.xml. The data is then rendered with the sample.xsl style sheet when it's loaded in the UIWebView.

Notice this line at the top of index.xml:
<?xml-stylesheet type="text/xsl" href="sample.xsl"?>
This tells the UIWebView to process the xml with the sample.xsl style sheet before displaying it in the view. This works exactly the same in the Safari web browser (other browsers also). In fact, you can generate a test xml file and do all your debugging in Safari before putting it into your app. It will save you a lot of time.

This sample is quite simple, but you're not limited to doing simple things. You can have a complete web application running in an Ikhoyo Web view by adding to index.xml and sample.xsl. It's a normal html page being generated and rendered, so anything a UIWebView accepts is valid.

Dynamic Tabs for the iPad

The UISplitViewController allows us to present a master/detail view for iPad apps. For an app with a complicated data model or many detail views, it can be useful to have the detail view use a UITabBarController as the container. In this post, I'll show you how to open multiple tabs in the detail view dynamically. In addition to the dynamic tabs, I'll also show you a few Interface Builder tricks that will cut your development time.

Each of the detail views will be contained in a UINavigationController. Using some IB tricks, we can put each detail view in it's own xib. As you know if you've read any of my previous posts, I'm a big fan of Interface Builder, and I think you should leverage it wherever possible. In this case we'll be using it wire almost the entire UI, with very little external code needed.

Go to GitHub and clone our repository. If you're using Xcode 4, look in the workspaces directory and open the ikhoyo-public workspace.

There are two projects in the workspace. One is called ikhoyo-top. It contains a 'kitchen sink' app showing all the techniques described on this blog. The other project is called ikhoyo-ui. It's a static library containing the UI classes that you can incorporate into your own projects or workspace.

The classes we'll be using are:
  • IkhoyoDynamicTabBarController - the detail view container. DetailViewController inherits from this class.
  • IkhoyoDynamicTabViewController - the base class for all the dynamic views. Each of the individual detail views inherit from this class. 
Click on SampleWebView.xib to see the detail view we'll be working with. It's basically a UINavigationController that contains an IkhoyoWebViewController. (I'll be showing you what an Ikhoyo Web View is in a future post). This xib may look a little funny, because there is still a view in here at the same level as the UINavigationController. This is the first Interface Builder trick I want to show you. If you attempt to instantiate this xib without the view, you'll get an error because the view cannot be located - even though the view is never used! You still need it connected to File's Owner so that the xib loading code will work. But it will be ignored since we'll be getting the UINavigationController to set as our root controller.

Open the Connections Inspector for File's Owner. File's Owner is SampleWebView, which is a subclass of IkhoyoDynamicTabViewController. The way we determine the root view controller in the xib file is by wiring it up to the root outlet. In this case, root is wired up the the UINavigationController. This is the controller we'll be dynamically adding to the DetailViewController's tab bar.

Now look in IkhoyoDynamicTabBarController. The addTab method is called to load the dynamic tab view. In this case, it will load the SampleWebView. Let's look at the code:

IkhoyoDynamicTabViewController* ctlr = [self hasTab:name];
if (!ctlr) {
    Class cls = NSClassFromString(c);
    ctlr = [[[cls alloc] initWithNibName:c bundle:nil] autorelease];
    ctlr.name = name;
    [ctlr view]; // Needed to force wiring in some cases
    ctlr.root.tabBarItem.title = name;
    if (image)
        ctlr.root.tabBarItem.image = image;
    NSMutableArray * vcs = [NSMutableArray arrayWithArray:
      [self viewControllers]];
    [tabs addObject:ctlr];
    [vcs addObject:ctlr.root];
    [self setViewControllers:vcs animated:NO];
}
[self setSelectedViewController:ctlr.root];
[ctlr start:param];
return ctlr;

The c variable contains the class name (SampleWebView). We use this to instantiate the xib. Basically, we instantiate the xib, get the root controller (which we wired up above), and add it to the tab bar's view controllers (via setViewControllers). You can also pass in the name and image that will appear in the tab bar item. Notice the [ctlr view] statement. This is related to the Interface Builder trick I described above. When we load the controller from the xib, all the wiring is not complete until the view in the xib is referenced. That's why we needed to put the view there, even though it's not used.

The addTab method is triggered from IkhoyoHomeTableViewController (in the ikhoyo-top project). To see it fire, put a breakpoint on the didSelectRowAtIndexPath method. If you start the app in the simulator and click on 'Sample Web View' in the master table view on the left, you can trace through and see how the addTab method works.

After the tab is loaded, the start method is called to do any view specific configuration. In our case, it starts the SampleWebView.

I've used Ikhoyo dynamic tab bars in several iPad apps that I've written. They're a very powerful technique to have in your toolbox for apps that have many detail views. We also learned some nice Interface Builder tricks that allow us to use IB in non-standard ways. In this case, we saw how we can make our code a bit more modular by having a UINavigationController based view residing in it's own xib file.

In the next post, I'll describe what an Ikhoyo Web View is, and why it's another powerful technique to have in our arsenal.

Sunday, May 22, 2011

Techniques for iPad and iPhone programming

I've been programming for the iPhone and iPad for a while now and would like to share some of the techniques I've developed to help the process.  Here are some of the topics I'll be discussing in future posts:

  1. iOS and Xcode are terrific tools, and I've learned to greatly appreciate Interface Builder.  You should leverage IB wherever possible, but IB has a fairly steep learning curve. I've developed many techniques for using IB in non-standard ways.
  2. Database programming with SQLite. I'll be posting the libraries that I use for SQLite development, and show how to build a custom version of SQLite.
  3. Web programming on iOS. I'll share some of the methods I use to incorporate local web applications in UIWebView. This is very handy for displaying all kinds of information.
  4. Network programming. I have an extensive network programming library that I'll be sharing.
  5. UIView layouts. I've developed several UIView layouts that incorporate nicely into IB.
  6. Lot's of other UIKit enhancements to make your life easy.