Simple iPhone Tutorial (Part 3)

With the completion of Part 2, the user interface of your application is almost ready. However, it does not serve much purpose since it does not interact with the users. In this last part of the tutorial, you will add in action handlers using addTarget API and @selector to capture user actions.

7. Adding Action Handlers Dynamically

We will now modify the OnOffTableCell and SliderTableCell classes to add in action handlers to handle events that are sent out when the user toggles the on/off switches or slides the bar in the slider control.

The (void)addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents and the @selector calls allow you to add your own handlers to handle events for any UIControl classes.

OnOffTableCell.m

onofftablecell5

SliderTableCell.m

Build and run the application. Open the debugger console in your XCode (Run > Console). You will see the debugging output that are being logged in the console as you toggle the switches and move slider in your first tab view.

You can download Source Code Bundle now to see for yourself how it works.

8. Communicating Changes Across

(There is an additional source code bundle at the bottom of this post which contains the source code for communication changes using notification)

You have learnt how to capture control events. But a sophisticated application do not normally act on such events within a single function. Often, there are multiple points scattered over the application that are focused on handling these events within the scope of their use cases. How can you announce these events to other modules that may be interested in them? And how to make these announcements in a way that the sender and the listeners are loosely coupled to each to the extent that they aren't even aware of each other's existence?

The iPhone SDK (or more specifically the Cocoa framework) defines the NSNotificationCenter class to facilitate such communications. If you are familiar with the Observer-Observable design pattern, the concept of NSNotificationCenter should not be unfamiliar to you. By using (void)postNotificationName:(NSString*)notificationName object:(id)notificationSender API function, the sender can post notifications to interested listeners. Both parties just need to agree upon the common notificationName to use.

We will now adopt the following communication methodology on top of the NSNotificationCenter class.

  • Each UILabel objects on the second tab view will listen for notifications from NSNotificationCenter and will have its own functions to update their text value to reflect the conditions of the controls they are listening to.
  • The cell rows that contain the UISwitch objects in the first tab view will listen and announce changes in the UISwitch value. The first row will use the notification name "SwitchForRow0" while the second row will use "SwitchForRow1". The notification names for each cell will be initialized in FirstTabViewController.m
  • The cell row that contains the UISlider object will listen and announce changes in the UISlider value over the notification name "SliderChanged".

The following code snippets illustrate how the postNotification and addObserver API calls are being used to link up the SliderTableCell and OnOffTableCell classes to the SecondTabViewController class. Notice that the SecondTabView class contains no references to the cell classes. The addObserver calls only contain the notification names.

SliderTableCell.m

OnOffTableCell.m

SecondTabViewController.m

FirstTabViewController.m

firsttabviewcontroller5

Build and run your application now. The labels in the second tab view will reflect the actions you have made on the UISlider and UISwitch controls in the first tab view.

9. Conclusion

Hope you have fun following this 3-part tutorial. Drop me any comments (good or bad) on how I can improve this tutorial :-)

Calculating MD5 Digest with iPhone SDK

The code originates from http://blog.andrewpaulsimmons.com/2008/07/md5-hash-on-iphone.html.

I have copied it here for mirroring purposes. Please express your appreciations to Andrew for his efforts.

#import <CommonCrypto/CommonDigest.h>

NSString* md5( NSString *str )
{
   const char *cStr = [str UTF8String];
   unsigned char result[CC_MD5_DIGEST_LENGTH];
   CC_MD5( cStr, strlen(cStr), result );
   return [NSString  stringWithFormat:
       @"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
       result[0], result[1], result[2], result[3], result[4],
       result[5], result[6], result[7],
       result[8], result[9], result[10], result[11], result[12],
       result[13], result[14], result[15]
   ];
}

Creating bin/cue Files on Linux

I have tested this to be working a Fedora Core 8 distro. It should work on other distros that have cdrdao installed. The following commands should be performed as a root user.

1. Scan for your device ID

$> cdrdao scanbus

You should see an output similar to the following:

Cdrdao version 1.2.2 - (C) Andreas Mueller
  SCSI interface library - (C) Joerg Schilling
  Paranoia DAE library - (C) Monty
Check http://cdrdao.sourceforge.net/drives.html#dt for current driver tables.
Using libscg version 'schily-0.8'
3,0,0 : Imation , IMWDVRW8I       , HSI3

Note the 3,0,0 at the bottom of the output. That's the device ID you need for the next command.

2. Now you can start copying the CD/DVD into a set of bin/cue file.

$> cdrdao read-cd --read-raw --datafile cdimage.bin --device 3,0,0  cdimage.cue

The above command will produce an image of the CD at device 3,0,0 (which is what I have gotten during the previous cdrdao command) and write the image into cdimage.bin and cdimage.cue.

You should see an output similar to the following when the command executes:

Cdrdao version 1.2.2 - (C) Andreas Mueller
  SCSI interface library - (C) Joerg Schilling
  Paranoia DAE library - (C) Monty
Check http://cdrdao.sourceforge.net/drives.html#dt for current driver tables.
Using libscg version 'schily-0.8'
3,0,0: Imation IMWDVRW8I        Rev: HSI3
Using driver: Generic SCSI-3/MMC - Version 2.0 (options 0x0000)
Reading toc and track data...
Track   Mode    Flags  Start                Length
------------------------------------------------------------
 1      DATA    4      00:00:00(     0)     00:06:00(   450)
 2      DATA    4      00:06:00(   450)     78:59:14(355439)
Leadout DATA    4      79:05:14(355889)
PQ sub-channel reading (data track) is supported, data format is BCD.
Raw P-W sub-channel reading (data track) is supported.
Cooked R-W sub-channel reading (data track) is supported.
Copying data track 1 (MODE2_RAW): start 00:00:00, length 00:06:00 to "cdimage.bin"...
Copying data track 2 (MODE2_RAW): start 00:06:00, length 78:59:14 to "cdimage.bin"...
Reading of toc and track data finished successfully.

Now you can open bin/cue file in Windows using DAEMON Tools. Try opening the bin file if you have an error opening the cue file.

Reuters NewsML Syndication Integration

The manual offered by Reuters explains how to write Java code to inform your web application of new stories from Reuters and how to extract the information from the NewsML files for your web site. This blog post will illustrate another way of integration by scanning the syndication folder for the NewsML files. The alternate method can be implemented in various programming languages such as Python, Perl, PHP or Ruby.

Introduction

Reuters Online Syndication offers a suite of ready to publish news stories for subscription by corporates. These news stories are categorized by geographical regions and by interests such as financial and sports. The syndication is not the same as the RSS feeds that you see on reuters.com; Reuters Online Syndication will push the latest breaking news, associated graphics and award-winning pictures to your site.

The Syndication Software

Your Reuters representative will pass you an URL or CD which contains the syndication software and your license key. The syndication software should be in a zipped or jar file, and will resemble something like this.

1. Unzip the zipped/jar file. Then create a license.key file in the same folder as the siclone.config. The first line of the license.key will contain the license key.

2. Now create a shell script in the same folder as the license.key

#!/bin/sh
PATH=.:$PATH
finish-upgrade.sh
launch-program.sh

With this shell script, the syndication software can be run on a command-line or as a service without the need for a graphical user interface. You can customize the shell script into a batch file for MS-DOS/Windows

3. Execute the shell script and when the syndication software is running, you should see a bunch of folders being created. Examples of these new folders are OLGBWORLD_iptc and OLUSPOLITIC_iptc. You will also see some XML and JPG files in these new folders. The XML files are the NewsML files which contain the Reuters stories while the JPG are the pictures and photos for some of the stories.

The folders or news channels are controlled by Reuters, so if you need more news channels, you need to call your Reuters representative. Each folder corresponds to one news channel. When the syndication software is running, it will write its status into siclone.config.

NewsML Files

Reuters has a good showcase for the NewsML format. The showcase contains some example NewsML packages which you can download to get a feel what are the key attributes in the NewsML files. You can also try out the NewsML toolkit from sourceforge.

By now, you can start coding your own application in your favourite programming language to scan the news folders at regular intervals for NewsML files. Once the syndication software has completed writing and closed the NewsML files, the files can be deleted from the folders without affecting the syndication software. Occasionally, you may come across files with filenames ending in .tmp. These are temporary files that the syndication software are using to dump the NewsML contents. Your application should ignore these temporary files.

The NewsML file contains numerous attributes which can be quite daunting initially. For starters, you can use a XML parser library that is available in your programming language and use it to parse out these attributes first:

  • DateTime
  • Role
  • USN
  • Slug
  • Headline
  • body

If you need to understand the classification for the story, you may also want to parse out the IPTCSubjectCodes and N2000 attributes as well. For more information on these attributes, call your Reuters representative :-)

All the contents (nodes) within the ... tag-pair will be the story that can be used to display to your audience. It is a well-formed xHTML document, so it can be included directly in any web page. In some stories, you will also find some RICs that are embedded within the body. You can replace these RICs using some regular expressions or convert them to valid URLs that link to the pages displaying the financial information for these codes.

This blog post has illustrated an alternative method of integrating with the Reuters syndication software which allows you to write your own NewsML processing routines in a non-Java language. It has also highlighted some NewsML attributes which you can look at first to start setting up your news site.

Use of Software Platforms (or Frameworks)

Software industry has been moving towards the adoption of software platforms in their products over the number of years. I don't mean platforms from SDK like .NET, C++ STL, or JDK. These are "essentials" to the language that they are supporting. Without them, these languages will be lying in software graveyards now. What I'm referring are platforms that bring in benefits other than language-based support for common coding tasks. These platforms generally provide an abstraction layer on top of the underlying programming interface to provide a more usable programming interface for the developers to work on. Examples:

  • Qt from Trolltech for cross-platform development on Windows, Linux, etc
  • Django, TurboGears, Pylons, Flex (and many more) for rapid web 2.0 application development
  • Microsoft Foundation Classes (MFC), Cocoa (OS X), KDE, Gnome for GUI development

In general, coding on these platforms usually lead to shorter development cycles (when you have learnt how to use them effectively). The more "utilities" these platforms provide, the less code you have to write and you can concentrate more on your application logic. However, there are certain trade-offs that come with the use of these platforms.

Performance

From my experience, any time saved during development will cost you more time during runtime. O-R mapping for database objects, cross-platform coding, etc saves you time from having to deal with low-level issues directly. However, the platform will consume extra milliseconds from doing all these work for you, so eventually these milliseconds will add up and snowball into a significant performance penalty.

Now, the trick to this is to see at which load that this snowballed penalty becomes so severe that it starts affecting the usability of your application. If you are lucky, your users might just accept it to be part of the network connectivity issues and just wait patiently. Otherwise, you can always argue that it's a happy problem that the performance issue is due to the wide acceptance of the public and request for more funding to buy more servers or more hardware.

Testing

When you adopt a software platform for use, you also assume the responsibilities to test the platform as well. In cases of bugs, you may also need to find workarounds or to work with the platform developers to fix these bugs. You should also consider situations when the platform developers may not be responsive or simply ignore your pleas for the bugs to be fixed and the platform source code may not be available for you to perform the debugging.

Installation

My advice: do your users a favor and choose a platform that is easy to install. You will end up giving yourself less headaches, trying to troubleshoot with your users why your application installs but gives runtime errors due to failed dependencies. (This is a common issue in Python unless you are using setuptools /ez_install to auto-install the dependencies).

For opensource platforms, take extra care to mirror your dependencies on your server. Good opensource projects release frequently, but sometimes the new releases may obsolete and change their function signatures, and end up breaking your application after the upgrades. Another issue to be take note is that the opensource projects can die out due to unforeseen circumstances, and the softwares just disappear on the Internet.

In times of Bad Luck...

What if you have made a bad choice and select the wrong platform only to discover that you need a more advanced feature? Sometimes, requirements can change drastically and end up affecting your fundamental assumptions which you have assumed when you decided that the selected platform is the best in terms of development costs and time needed.

This has happened to me once when I had used Django for one project only to discover later that I needed to use vertical partitioning to re-model my data models because not all data reside in a single database. Pylons or TurboGears with SQL Alchemy can resolve this issue, but not Django as its O-R engine is built on the assumption that you need only one database for all your models.

Conclusion

To conclude, software platforms are useful and handy to work with, but there are cons which you need to evaluate carefully before deciding on their use. Otherwise, you may find yourself in sticky situations when it's really difficult to resolve without a full rewrite.