iPhone-App Development for Web Hackers
on July 19, 2008So here is my situation: I’ve been doing solely web development over the past two years and am still very busy working for a startup in Tokyo. The iPhone 3g just went out and I want to build a cool prototype that utilizes GPS. Over the past week I’ve spent a couple of hours here and there to make a little proof-of-concept application. I wasted some time running around in panic so hopefully this article will help to get you focussed.
Allright, this is what this prototype should be doing:- Being able to access location information.
- Show a map with a marker for the current location.
- Get relevant information about that current location and show that in an ‘info’ tab.
Safari is so Amazing
It seems that Safari on the iPhone can accommodate all user interface needs for a non-gaming application. Also, if you really want to do graphics stuff, there is some cool vector rendering CSS you can do.
Joe Hewitt wrote a little CSS/JavaScript pack called IUI. It makes your web applications in Safari look like native iPhone apps. Awesome!
If it was up to me, I would be coding everything in Safari. Server-side Rails, Ajax and accessing iPhone Hardware through Javascript – the wet dream of any Web Hacker. Unfortunately the latter is not (yet) possible, so we will have to build a hybrid web application.
iPhone Safari specific JavaScript capabilities:- Storing data locally through SQL
- Get the physical orientation of the device.
More in this video (Click on “iPhone SDK for Web Developers”)
The Magic
Bottom line is that we don’t want to waste time and keep on programming web. Since we want to access hardware information, we will have to get down and dirty with the iPhone SDK. Our goal: Render a Safari Component and push GPS information through JavaScript and AJAX to the web application.
Programming Cocoa
Note: I am very convinced that in order to learn any language, you should just jump in right away – don’t build useless example projects.
The Cocoa set of tools is called Cocoa Touch and provides all the UI and Data Access things you need. On the iPhone you program in Objective-C 2.0 whatever the fuck that might be :] Aahrgh, so I have been doing Ruby for the past two years and I have a vague memory of C++. Ah well, Objective-C is just another OO programming language, so it shouldn’t be that big a deal.
This video explains basic Objective-C syntax (forward to 3:00): http://developer.apple.com/iphone/index.action (Click on “iPhone Application Development – Getting Started”). It will explain a bit about Cocoa’s Model View Controller which might be useful.
Don’t waste your time on Hello World
When downloading HelloWorld and opening that in XCode (apple’s IDE) I got freaked out by the amount of code and files. Normally, when learning a new technology, I take examples and re-purpose them for my project. This will not work right away for Cocoa Touch.
Note: many coding screencasts use old versions of XCode or Interface Builder. Make sure your SDK is up to date and that the screencast you’re watching isn’t using older versions.
The catch is that you need to use a thing called Interface Builder to stitch together your Objective-C code with UI Components. So it’s better to watch a little screencast. This Screencast will show you how to add a couple of buttons and hook them up to a specific callback. The dude talks very slow so you can fast-forward every now and then.
After that this screencast will show you how to jack in the Magic UIWebView – our precious Safari. In this screencast they hook up two buttons (back and forward) to the UIWebView.
Our first Application
Assuming you have downloaded the iPhone SDK. Mac programming is mostly done using an IDE called ‘XCode’. It can be found in the /Developer directory of your Mac.
Let’s create a new Project in XCode, I am using the name ‘Reccoon’, but I will refer to it as ‘MyProject’:

Next, double-click on the Resources/MyProjectViewController.xib. This will open up the Interface Builder. Thereafter, cover the whole window with a safari UIWebView:

To access that ‘web view’ in the controller, we need to add a class attribute to the MyProjectViewController. This is called an ‘external outlet’:

Also, you need to add some code in your MyProjectViewController.h to utilize it as you can see in the next piece of code.
Hooking up CoreLocation
Now let’s get some code from the LocateMe example that can be found in the iPhone Dev center and add MyCLController.* and the CoreLocation Framework:

Set this code to your MyProjectViewController.h
1 2 3 |
@interface ReccoonViewController : UIViewController <MyCLControllerDelegate> { IBOutlet UIWebView *webView; } |
The LocateMe example’s MyCLController has all kinds of funky debug output. We only want the Latitude and Longitude, so let’s modify a bit.
In MyCLController.h:1 2 3 4 5 6 7 |
// This protocol is used to send the text for location // updates back to another view controller @protocol MyCLControllerDelegate <NSObject> @required -(void)updateLatitude: (NSString *)latitude andLongitude: (NSString *)longitude; -(void)newError:(NSString *)text; @end |
In MyCLController.m, replace the method: locationManager didUpdateToLocation fromLocation, with:
1 2 3 4 5 6 7 8 9 10 11 12 |
// Called when the location is updated - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation { [self.delegate updateLatitude: [NSString stringWithFormat:@"%lf", fabs(newLocation.coordinate.latitude)] andLongitude: [NSString stringWithFormat:@"%lf", fabs(newLocation.coordinate.longitude)]]; } |
Now implement the necessary callbacks. (this code belongs before the @end in the ReccoonViewController.m)
1 2 3 4 5 6 7 8 9 10 11 |
#pragma mark ---- delegate methods for the MyCLController class ---- -(void)updateLatitude:(NSString *)latitude andLongitude:(NSString *) longitude { [webView stringByEvaluatingJavaScriptFromString: [NSString stringWithFormat:@"update_position(%@, %@);", latitude, longitude]]; } -(void)newError:(NSString *)text { [self debug: [NSString stringWithFormat:@"error: %@", text]]; } |
As you might see in the updateLatitude function, a Javascript call is executed on the webView Safari browser. This means that you can do all your positioning and maps mashupping in Javascript:
1 2 3 |
function update_position(lat, lng) { /* We have escaped from Alcatraz! Now it's time for AJAX and JSON goodness :] */ } |
My Reccoon Prototype
For my own purposes, I’ve made a little RubyOnRails project (pretty much all HTML) that uses the Google Maps API and the Geonames Wikipedia Reverse-Geocoding Service. This utilizes the IUI toolkit:



Note: in these screenshots I am simulating the location to be in Amsterdam (while I am still in Tokyo). The iPhone Simulator’s default GPS coordinates are somewhere in the western Chinese badlands.
Conclusion
Perhaps Cocoa development isn’t as scary as it seems, after the useful-results feedback loop started (getting into the flow) I was really enjoying it. This little prototype is just an example on how to quickly get some results for a demonstration application. I can imagine that more and more Cocoa programming is necessary when the product/service starts to evolve.
I know this article is a sloppy quick write-up, but if you find it useful please leave a digg :] Also, please place a comment below if you have any problems or questions – I will address them by updating this entry.
YC News Bookmarklet using Yahoo Pipes
on May 21, 2008Yesterday I had a long phone call with my friend Peter Tegelaar about the usual stuff that interests us: the web, startups, the semantic web, natural language parsing, mobile web, recommendation engines etc. At a certain point we came to discuss his YCombinator News karma and it got me thinking about what a nice way it is to highlight quality content in a system.
The news submission to YCombinator News (Hacker News) is very important too one's karma. The trick is to submit news that is new, original and intellectually aligned with the YC community. So I thought it would be nice to have a bookmarklet to submit entries to HN, and naturally that bookmarklet already exists.
However, the current bookmarklet is lacking a feature I thought would be very useful:- If the URL is already submitted, don't submit but go to the comments page of that URL.
- If the URL is new, go to the submission page.
here is the final resulting bookmarklet, to install drag this to your bookmark bar (IE7 and Firefox tested)
to YC News
- A JSON feed of the top entries.
- A JSON feed of the recently submitted entries.
Some of you might know that I've made the little project Wigitize.com. Basically wigitize is a simple RSS to JSON converter. However, with Yahoo Pipes you can do a lot more. Using Yahoo Pipes I've made two data feeds that can be represented in numerous formats including JSON:
- HN Newest, a pipe that scrapes the newest page using a maze of regular expression renames.
- HN Top and Newest, a combined feed of the top and newest entries (uses the first pipe).
While using Yahoo Pipes I had to do a lot of hacking and screwing around to scrape the page, something I could've done far more quickly using conventional scripting. Heard of any such service?
The resulting bookmarklet is build upon the original by Phil Kast. It uses the Top and Newest Yahoo Pipe to determine whether an article has been submitted already (of course the pipe will lag behind a bit in time, so it will not work perfectly).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
function to_hacker_news(pipe) { var items = pipe.value.items; var url = 'http://news.ycombinator.com/submitlink?u='+encodeURIComponent(document.location)+'&t='+encodeURIComponent(document.title); for(var i=0; items.length > i; i++) { if(items[i]['link'] == document.location) { url = items[i]['comments']; } } window.location = url; }; function bookmark_to_hacker_news() { var script = document.createElement('script'); script.src='http://pipes.yahoo.com/pipes/pipe.run?_id=emucF0ci3RGfI6mHxAnzeQ&_render=json&_callback=to_hacker_news'; document.getElementsByTagName('head')[0].appendChild(script); }; bookmark_to_hacker_news(); |
I don't use YC News as often as I should, but I've decided to roll it into my habits. Because of that I might as well have solved a problem that was in no way worth solving (conceptual mistake), but I did have a chance to practice making my first Pipe and Bookmarklet.
Peter noted that it would be nice to upgrade this bookmarklet to support bookmarking directly from Google Reader. Any takers? That would be a nice hack indeed!
AJAX snippet: Blank out a Div with a Spinner
on December 16, 2007While doing some quick prototyping for one of my projects I was building a week, month, year period selector. When loading stuff with AJAX it is important to indicate to your users that you are actually refreshing a piece of data on your page. There are many ways of indicating this load, but for now I just wanted something quick and useful (without requiring any strings that might have to be translated in the future):
example data:

when loading:

I meshed together a quick piece of Javascript and CSS since I couldn’t find anything out there. If you know something that does this, please let me know! (Since my code is obviously quick and dirty and only tested on Firefox).
Put this in one of your Javascript files (in case of rails: application.js):
1 2 3 4 5 |
function spin_div(div_id) { container = $(div_id); positioning = 'top: '+container.offsetTop+'px; width: '+container.offsetWidth+'px; height: '+container.offsetHeight+'px; '; container.innerHTML += '<div class="spin_div" style="position: absolute; ' + positioning + '"></div>'; } |
And here is some CSS which you can customize (spinner.gif is a generated spinner from ajaxload.info):
1 2 3 4 5 6 7 |
.spin_div {
background: #fff url('/images/spinner.gif') no-repeat center center;
opacity: 0.75;
filter:alpha(opacity: 75);
-moz-opacity: 0.75;
-khtml-opacity: 0.75;
}
|
Now when using Rail’s or prototype’s AJAX routines, just pass spin_div as a onLoad parameter:
1 |
link_to_remote('label', :url => takes_awhile_url, :loading => "spin_div('container_id');") |
The great thing about this method is that the spinner get’s automatically destroyed when the content of the container is refreshed.

