I recently came out with two iOS-based eBooks, using my own framework: Leadership @ Work and Don't Just Retire!. Here's the story behind the books and the framework.
(By the way these books are half price sale until September 18 2012!)
The previous post talked about the books and the basic ideas behind the framework. This one gets technical and covers not one but three different languages. Hold on to your hats.
Getting and Setting Form Values
It's one thing to show static content in a set of web pages inside UIWebViews in an app. But what about letting the user type things into fields on these web pages? The iOS experience is quite different from the web experience: content should be loaded and saved invisibly and effortlessly behind the scenes, without any user interaction. If you go to a new page, the old page's data should be stored, and the new page's data should already be present. If you have a "SAVE" button in an iOS app, you're doing it wrong.
After a lot of consideration and even more tinkering, I came up with a solution that seemed kind of precarious at first but turned out to run very well:
Thankfully all of the field values are plain text, and even if a user entered huge amounts into every field of every page, the entire data set would probably still be below a megabyte. iOS devices can easily store this amount of data in RAM, and even persistence to a file to flash storage is practically instantaneous.
Building the Content: Ruby to the Rescue
So, I had figured out a way to get data into and out of web pages, but I still needed to assemble dozens if not hundreds of pages of HTML for both the content and the forms. These had to have consistent layout, and the files needed to be organized enough to be easy to manage from within the app.
Back in the early 2000s, I built several static but complicated web sites for clients by merging content files into templates. The earliest ones were done using BBEdit
's multi-file search and replace tools. Then OS X came out and I discovered the UNIX command line and I built another site entirely using sed
- but then I came to my senses and redid it in Perl, which was easier to maintain and ran much faster.
Since I'm a Rails developer, I now use Ruby for this kind of thing. While, most of the talk about Ruby in the last five years or so has been about Rails, people often forget how great Ruby is for Perl-like 'glue' tasks such as file munging
. I frequently use Ruby when I need to parse or convert big log files, CSVs, or database dumps. Setting up all of these HTML files turned out to be another perfect fit.
tags for things like the page number, the title, and the page contents:
<h1><%= title %></h1> <%= pagecontents %>
Then I built HTML files for each chapter, with sequentially coded names like 'A01.html', 'A02.html' etc. The files are mostly plain HTML, with some special shortcut tags for things like fields.
The key piece of this is a 'data.rb' file, which is basically a large Ruby data structure that describes each of the pages in the book in order with a unique identifier, a listing name, the template type, and other criteria. Here's a sample entry:
This is all processed by a 'builder.rb' script. This script does a lot:
- Goes through each entry in the data.rb file and finds the related source html file.
- Merges the parsed content into the appropriate template file.
- Saves the resulting merged file with the specified name.
- Adds an entry to an 'AppData.plist' file for the iOS app.
With all these source files and templates and configuration settings in various languages and formats, there's a big risk of things getting confused and messed up. This is solved by having one definitive source: the 'data.rb' file. Everything else comes out of there, generated by the builder.rb script - including the 'AppData.plist' file that is used by the iOS app as the main book reference. This way as long as the data.rb file is correct (and the files it refers to are in the right place) everything else fits together automatically. Whenever I make a change to one of the source files, I just re-run the builder.rb script and all of the other files and configurations are set up automatically.
The next post will discuss the business side of these apps.