Mac / iPhone App Development
Home of a Small Time Developer
#include <stdio.h>
#include <time.h>
#include <netinet/in.h>
typedef struct { int ID; char * title; char * link; char * date; int upVotes; int downVotes; void * next; } Article; Article * root; char * getVal(char * query, char * key) { char * str = malloc(1); int match = 0; int pMatch = 0; char * cur = query; while (*cur != '\0') { if (pMatch >= 1 && (*cur == '&' || *cur == '\n' || *cur == ' ')) { break; } else if (pMatch >= 1) { str = realloc(str, pMatch+1); *(str+pMatch-1) = *cur; ++pMatch; } else if (match == strlen(key)) { pMatch = 1; } else if (*cur == key[match]) { ++match; } else { match = 0; } cur++; } if (pMatch >= 1) { str[pMatch-1] = '\0'; return str; } free(str); return NULL; } char from_hex(char ch) { return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10; } char to_hex(char code) { static char hex[] = "0123456789abcdef"; return hex[code & 15]; } char *url_decode(char *str) { char *pstr = str, *buf = malloc(strlen(str) + 1), *pbuf = buf; while (*pstr) { if (*pstr == '%') { if (pstr[1] && pstr[2]) { *pbuf++ = from_hex(pstr[1]) << 4 | from_hex(pstr[2]); pstr += 2; } } else if (*pstr == '+') { *pbuf++ = ' '; } else { *pbuf++ = *pstr; } pstr++; } *pbuf = '\0'; return buf; } void send_headers(FILE *f, int status, char *title, char *extra, char *mime, int length) { char timebuf[128]; fprintf(f, "%s %d %s\r\n", "HTTP/1.0", status, title); fprintf(f, "Server: %s\r\n", "redditserver/1.0"); if (extra) fprintf(f, "%s\r\n", extra); if (mime) fprintf(f, "Content-Type: %s\r\n", mime); if (length >= 0) fprintf(f, "Content-Length: %d\r\n", length); fprintf(f, "Connection: close\r\n"); fprintf(f, "\r\n"); } void reddit(FILE *f) { fprintf(f, "<HTML><HEAD><TITLE>Reddit Clone</TITLE></HEAD>\r\n"); fprintf(f, "<BODY><H1>Submit</H1><form action=\"/\" method=\"get\">Title:<input type=\"text\" name=\"title\" /> Link:<input type=\"text\" name=\"link\" /><input type=\"submit\" value=\"Submit\" /></form>\r\n"); if (root) { fprintf(f, "<h1>Articles</h1>"); Article * cur = root; while (cur != NULL) { fprintf(f, "<p><font size=\"5\">%d<b><a href=\"/?up=%d\">&uarr</b></font><a href=\"%s\">%s</a><br /><font size=\"5\"> <b><a href=\"/?down=%d\">&darr</a></b></font>%s -- %s</p>", cur->upVotes - cur->downVotes, cur->ID, cur->link, cur->title, cur->ID, cur->link, cur->date); cur = cur->next; } }fprintf(f, "</BODY></HTML>\r\n"); } int fsize(FILE * f) { fseek(f, 0, SEEK_END); int size = ftell(f); fseek(f, 0, SEEK_SET); return size; } int main(int argc, char *argv[]) { int sock; int port = 1337; struct sockaddr_in sin; sock = socket(AF_INET, SOCK_STREAM, 0); sin.sin_family = AF_INET; sin.sin_addr.s_addr = INADDR_ANY; sin.sin_port = htons(port); while (bind(sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) { printf("Failed bind\n"); sleep(2); } listen(sock, 5); printf("HTTP server listening on port %d\n", port); root = NULL; while (1) { int s; int size; int hsize; char * buff; FILE * t; FILE * ht; FILE * f; s = accept(sock, NULL, NULL); if (s < 0) break; char * header = calloc(255, 1); size = read(s, header, 255); char * titleEnc = getVal(header, "title"); char * linkEnc = getVal(header, "link"); if (titleEnc && linkEnc) { char * title = url_decode(titleEnc); char * link = url_decode(linkEnc); free(linkEnc); free(titleEnc); printf("Title: %s -- Link: %s\n", title, link); char * s = malloc(30); size_t i; struct tm tim; time_t now; now = time(NULL); tim = *(localtime(&now)); i = strftime(s,30,"%b %d, %Y; %H:%M:%S\n",&tim); Article * new = malloc(sizeof(Article)); new->title = title; new->link = link; new->next = NULL; new->date = s; new->upVotes = 0; new->downVotes = 0; if (!root) { root = new; new->ID = 0; } else { int dupe = 0; Article * cur = root; Article * prev = NULL; while (cur != NULL) { if (strcmp(cur->title, new->title) == 0 || strcmp(cur->link, new->link) == 0) { dupe = 1; } prev = cur; cur = cur->next; } if (dupe == 0) { new->ID = prev->ID + 1; prev->next = new; } else free(new); } } char * upID = getVal(header, "up"); if (upID) { int ID = atoi(upID); Article * cur = root; while (cur != NULL) { if (cur->ID == ID) { cur->upVotes++; break; } cur = cur->next; } } char * dID = getVal(header, "down"); if (dID) { int ID = atoi(dID); Article * cur = root; while (cur != NULL) { if (cur->ID == ID) { cur->downVotes++; break; } cur = cur->next; } } t = tmpfile(); ht = tmpfile(); reddit(t); size = fsize(t); send_headers(ht, 200, "Ok", NULL, "text/html", size); hsize = fsize(ht); buff = malloc(hsize); fread(buff, 1, hsize, ht); write(s,buff,hsize); free(buff); buff = malloc(size); fread(buff, 1, size, t); write(s,buff,size); free(buff); fclose(t); } }

$ gcc reddit.c -o reddit
$ ./reddit
HTTP server listening on port 1337 — http://localhost:1337/
reddit.c
Working with core data in a multi threaded environment you have to extremely careful
For example if were creating a news application, we want to be able to import news in the background and display updates to the user with no interruption of the GUI. The task can be divided into several stages:
- Download the xml feed with the latest news
- Parse the feed
- Insert the articles into core data
- Notify the UI and refresh the display.
We already have our core data API defined. A simple method to retrieve all the articles and a method to add a new article.
DataSource.h
@interface DataSource : NSObject { }
-(NSArray*)getNewsFor:(Region*)region;
-(void)addArticle:(Article*)article forRegion:(Region*)region;
@end
}
Now suppose we want to the web service to import the latest articles. We might define our implementation something like this:
WebService.h
@interface WebService : NSObject {
id delegate;
LocalDataSource * source;
}
@property(nonatomic, retain) id delegate;
@property(nonatomic, retain) LocalDataSource * source;
-(void)importNewsForRegion:(Region*)region;
@end
Our implementation of importNewsForRegion would look something like this:
WebService.m
-(void)importNewsForRegion:(Region*)region
{
//Perform in background if called from main
if ([NSThread currentThread] == [NSThread mainThread])
{
[self performSelectorInBackground:@selector(importNewsForRegion:) withObject:region];
return;
}
//Setup pool
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSArray * articles = [XML parseArticleFeed:region.feedURL]; //Not safe 1.
for (Article * article in articles)
{
[source addArticle:article forRegion:region]; //Not safe 2.
}
[delegate finishedImport]; //Not safe 3.
[pool drain];
}
However this because importNewsForRegion is running in a separate thread this is unsafe and will likely cause core data to crash or corrupt our database.
- The region passed to to importNews has likely come from a core data context which was constructed on the main thread. Even though were not even altering the region directly with core data it’s not safe to even read the feedURL, because every operation can trigger faulting.
- When we instruct the source to add an article it will use the main threads context, this is fine when we are in the main thread, but in a background thread we need to specify our own context.
- Not related to core data, but when we notify the delegate it will likely perform UI updates which are not safe to perform in a background thread. we need to ensure the delegate only received notifications on the main thread.
To make our program thread safe we first need to make some small alterations to our API.
DataSource.h
@interface DataSource : NSObject { }
-(NSArray*)getNewsFor:(Region*)region;
-(NSArray*)getNewsFor:(Region*)region context:(NSManagedObjectContext*)context;
-(void)addArticle:(Article*)article forRegion:(Region*)region;
-(void)addArticle:(Article*)article forRegion:(Region*)region context:(NSManagedObjectContext*)context;
@end
}
In our data source we specify two more methods which allow us to provide a context for the method to use. All our queries should be updated to only use the provided context. The original methods that don’t specify a context should call the newly implemented method with the default context, e.g.
-(void)addArticle:(Article*)article forRegion:(Region*)region
{
[self addArticle:article forRegion:region context:mainThreadContext];
}
Only when we are using core data in a background thread do we need to use the newly added methods. So we can now update our WebService.m:
-(void)importNewsForRegion:(Region*)unsafeRegion
{
//Perform in background if called from main
if ([NSThread currentThread] == [NSThread mainThread])
{
[self performSelectorInBackground:@selector(importNewsForRegion:) withObject: unsafeRegion];
return;
}
//Setup pool
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
//Create a new context just for this thread
NSManagedObjectContext * managedObjectContext = [[NSManagedObjectContext alloc] init];
[managedObjectContext setPersistentStoreCoordinator: [source persistentStoreCoordinator]];
//Create a new region which is safe to use in this thread
Region * region = (Region*)[managedObjectContext existingObjectWithID:[unsafeRegion objectID] error:nil];
NSArray * articles = [XML parseArticleFeed:region.feedURL];
for (Article * article in articles)
{
//Ensure we provide the context for the source to use
[source addArticle:article forRegion:region context:managedObjectContext];
}
//Save changes and close the new context
[managedObjectContext save:&error];
[managedObjectContext release];
[delegate performSelectorOnMainThread:@selector(finishedImport) withObject:nil waitUntilDone:NO];
[pool drain];
}
As you can see we crate a new context using out shared persistentStoreCoordinator, we ensure that anytime we touch core data from this thread we are using this context. The also means that we have to create a new region which belongs to this context, and we do this with the existingObjectWithID method and using the [unsafeRegion objectID]. Finally we ensure that the delegate receives the notification on the main thread.
for more information about threading in core data see:
http://developer.apple.com/Mac/library/documentation/Cocoa/Conceptual/CoreData/Articles/cdMultiThreading.html
Cocos2d is a popular 2d framework for developing iphone games, including physics and particle support. Here’s a quick introduction to getting cocos2d for the iphone up and running for your next project.
Download the latest source from:
http://code.google.com/p/cocos2d-iphone/downloads/list
I recommend you stick with the stable releases, unless there is a specific feature your require from a new version.
Unzip the folder and the template installation script:
$ ./install_template.sh
This will make a series of cocos-2d templates available from XCode. Launch/restart xcode and choose File->New Project->cocos2d Application build and run the new application in the simulator and it should look something like this:

Were going to build on this template to add a main menu
First download the test image and add it to the new xcode project (Make sure it is copied into the application directory)

Create a new class name MenuScene and add the following code to the header file:
#import
#import "cocos2d.h"
@interface MenuScene : Scene
{
}
@end
@interface MenuLayer : Layer
{
}
-(void)startGame: (id)sender;
-(void)help: (id)sender;
@end
The add the following to the .m file:
#import "MenuScene"
@implementation MenuScene
- (id) init
{
self = [super init];
if (self != nil) {
Sprite * bg = [Sprite spriteWithFile:@"MainMenuBackground.png"];
[bg setPosition:ccp(160, 240)];
[self addChild:bg z:0];
[self addChild:[MenuLayer node] z:1];
}
return self;
}
@end
@implementation MenuLayer
- (id) init
{
self = [super init];
if (self != nil)
{
[MenuItemFont setFontSize:24];
[MenuItemFont setFontName:@"Helvetica"];
MenuItem *start = [MenuItemFont itemFromString:@"Start Game"
target:self
selector:@selector(startGame:)];
MenuItem *help = [MenuItemFont itemFromString:@"Help"
target:self
selector:@selector(help:)];
Menu *menu = [Menu menuWithItems:start, help, nil];
menu.color = ccc3(0, 0, 0);
[menu alignItemsVertically];
[self addChild:menu];
}
return self;
}
-(void)startGame: (id)sender
{
NSLog(@"start game");
}
-(void)help: (id)sender {
NSLog(@"help");
}
@end
Finally modify the app delegate (CocosTestAppDelegate.m) to include MenuScene.h
#import "MainMenuScene.h"
and replace the line:
[[Director sharedDirector] runWithScene: [HelloWorld scene]];
with:
[[Director sharedDirector] runWithScene: [MenuScene node]];
also remove the line:
[[Director sharedDirector] setDeviceOrientation:CCDeviceOrientationLandscapeLeft];
Compile and run the project and you should end up with a menu and two clickable buttons:

I’ve been meaning to redesign benreeves.co.uk for a while, however there were two things stopping me:
- Graphics / Html have never been my strong point. Sure I can cut and paste from other designs and cobble together something which resembles a web page, but they always look just that, cobbled together.
- It doesn’t get much traffic or provide much business value at present and hence I don’t want to have to pay a designer.
I had previously used iWeb and then up until recently rapidweaver, these applications are fine up to a point, but soon there lack of advanced features and template editing becomes apparent. Between an application like iWeb and designing the site from scratch we have content management systems (CMS), the most popular being Drupal, Joomla and wordpress.
I had heard good reviews of Drupal before so this was my first port of call. I won’t go into detail about the setup, but it was overall fairly straight forward, however after that things went downhill. The admin panel was confusing and slow, I spent several hours trying to get the sites navigation and content to resemble something how I wanted. It seemed like every theme I tried ended up looking like the same boxy layout, you could immediately tell the site was using drupal. The themes were poor quality, difficult to modify and modules were complicated to install. After my drupal experience I gave up on CMS for a while.
Today I decided to give wordpress a shot. Since I already had php setup, Installation really was a case on unpacking the zip file and placing it in the apache home directory. I immediately went to install a new template. Wordpress features an automatic template installation system, however this is where I hit my first stumbling block. Wordpress kept asking for my ftp information, however a quick google search revealed my file permissions were wrong.

The following command did the trick: sudo chmod -R 777 /Path/To/Wordpress
Other than that templates where easy to install and I had found several decent looking ones in a few minutes. The next task was to add a contact page, unfortunatly wordpress doesn’t come with one as standard however the plugin “Contact Form 7″ was easy to install without leaving the admin interface. Even the more advanced task of separating the wordpress blog into two different pages (see The Loop) could be done without leaving the admin interface.
Overall I have been extremely impressed so, maybe I’ll run into customisation limitations again later, however at the moment I can’t praise wordpress enough.
Ok so iVersion 1.4 was declined due to not loading correctly when their is no network connectivity.
When the device is connected to a cellular network, iVersion does not load its contents. After the user enters the URL (http://svn.collab.net/repos/svn/trunk/) and taps “connect,” an error message is received.
Apparently the error message is not clear enough or something, anyway this is not a rant, this is what apple recommends.
Please take a look at the Reachability iPhone program sample which demonstrates the use of the System Configuration Reachability API to detect the absence of WiFi and Wireless Wide Area Network (WWAN) services. Your application can then take appropriate action at the first point where network services are required.
The sample code can be found on Apple developer site, however the two file we are interested in are:
Download the Reachability Code:
Reachability.h
Reachability.m
How to use:
Lets say you have a simple UILabel which you want to update with either “(Offline)” or “(Online)” depending on whether the network is reachable. Your view controller would be defined something like this:
@interface MyStatusView : UIViewController
{
UILabel * statusLabel;
}
@property(nonatomic, assign) IBOutlet UILabel * statusLabel;
- (void)reachabilityChanged:(NSNotification *)note;
- (void)updateStatus;
@end
Then we add the following code to the view controller .m file:
-(void)viewWillAppear:(BOOL)animated
{
self.reachability = [Reachability reachabilityWithHostName:@"google.com"];
[reachability startNotifer];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reachabilityChanged:) name:@"kNetworkReachabilityChangedNotification" object:nil];
[self updateStatus];
}
-(void)viewWillDisappear:(BOOL)animated
{
self.reachability = nil;
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
-(void)reachabilityChanged:(NSNotification*)notification
{
[self updateStatus];
}
-(void)updateStatus
{
NSLog(@"Reachability changed");
if ([reachability currentReachabilityStatus] == NotReachable)
{
statusLabel.text = @"(Offline)";
}
else
{
statusLabel.text = @"(Online)";
}
}
I think it’s fairly self explanatory. Basically when the view appears the reachability class is created and started using startNotifier. Then we hook in our reachabilityChanged: method into the notification centre, so it is automatically called when the network status changes. reachabilityChanged: calls updateStatus which simply changes our label depending on the connectivity.
in order to not lock the ui iVersion runs it’s svn commands in a seperate threads. The promblem arises when one of thses threads needs to prompt for a value e.g. a username / password. Firstly UIKit does not provide a modal alert view and secondly UIKit should only be called from the mainThread.
First we create a new class which has a view which will be loaded from a nib, a thread condition to lock the calling thread and two NSString fields to store the result and the string of the button which was clicked.
@interface MessagePrompt : NSObject
{
UIView * view;
NSCondition * promptCondition;
NSString * clickedButton Text;
NSString * result;
{
@end
Our new prompt method can be called from the thread which needs to be locked, it will subsequently call UIKit on the main thread.
+(id)newPrompt:(MessagePrompt*)prompt
{
if ([NSThread currentThread] == [NSThread mainThread])
{
printf("Should not be called by Main thread\n");
return nil;
}
prompt.promptCondition = [[[NSCondition alloc] init] autorelease];
[prompt performSelectorOnMainThread:@selector(prompt:) withObject:view waitUntilDone:NO];
[prompt.promptCondition wait];
return prompt;
}
This method is called by +(id)NewPrompt and displays a prompt in our window. It also adds targets to each UIButton to receive user actions.

-(void)prompt:(UIView*)inView
{
NSArray * nib = [[NSBundle mainBundle] loadNibNamed:@"MyPromptView" owner:self options:nil];
inView = [nib objectAtIndex:0];
NSArray * subviews = [self.view subviews];
for (UIView * cview in subviews)
{
if ([cview isKindOfClass:[UIButton class]])
{
UIButton * button = (UIButton*)cview;
[button addTarget:self action:@selector(clicked:) forControlEvents:UIControlEventTouchDown];
}
}
[inView.superview addSubview:view];
}
This is called when a user clicks a button, it finds the value field and retreives and stores the value in self.message. The prompt condition is then signalled which causes the calling thread to continue running.
-(IBAction)clicked:(UIButton*)sender
{
self.clickedButton = sender.currentTitle;
UITextView * text = [iVersionAppDelegate findSubViewOfKind:self.view class:[UITextView class]];
if (text)
{
self.message = text.text;
}
[self.view removeFromSuperview];
self.view = nil;
[promptCondition signal];
}
@end
Usage
/* Called when svn requires a log message */
svn_error_t *
iversion_svn_cl__get_log_message(const char **log_msg,
const char **tmp_file,
const apr_array_header_t *commit_items,
void *baton,
apr_pool_t *pool)
{
CommitLogMessagePrompt * prompt = [CommitLogMessagePrompt newPrompt];
/* Clicked Continue */
if ([prompt.clickedButton isEqualToString:@"Continue"])
{
*log_msg = [prompt.message UTF8String];
return SVN_NO_ERROR;
}
return svn_error_create(SVN_ERR_CANCELLED, NULL, _("Delete Cancelled"));
}
I require simple for system monitoring for a new (undisclosed) iphone project. It doesn’t appear that there is any equivilant to ionotify for the iphone, so I whipped up this polling file system monitor which meets my basic requirements. If you find this code useful feel free to use / distribute etc.
#include "FileSystemMonitor.h"
//Setup the monitor
FileSystemMonitor * monitor = [[FileSystemMonitor alloc] init];
monitor.delegate = self;
[monitor monitorPath:@"/"];
//...In your delegate class
-(void)nodeWasCreatedAt:(NSString*)path
{
printf("Created %s\n", [path UTF8String]);
}
-(void)nodeWasDeletedAt:(NSString*)path
{
printf("Deleted %s\n", [path UTF8String]);
}
-(void)fileSizeDidchange:(NSString*)path bytes:(size_t)difference
{
printf("file Added %ul bytes\n", difference);
}
Notes:
- Can monitor for Deleted files, Created Files and File Size Changes
- On an iPhone 3GS it is able to monitor the entire SVN 1.6 source tree and the iVersion source tree (total 11,050 File/Directories) in an execution time of 12s. Due to the low thread priority and the fact that the majority of execution time is IO it does not cause much/any slow down to the UI. However there is still room for improvement.
Download:
FileSystemMonitor.h
FileSystemMonitor.m
FileMonitorDelegateProtocol.h
In the final push to add syntax highlighting to iVersion I have been working on optimising the parser.
In the inner parsing loop I have been using the standard NSMutableArray to keep track of various objects and tokens. Objective C message passing is of course an order of times slower than a C function call, even if purely for the fact that they can’t be inlined. A great article that explains more about the objective c runtime an be found on the cocoa samurai blog
So I decided to drop down to a dynamic array using plain C. However even though I’m sure dynamic arrays have been implement thousands of times I couldn’t seem to find any simple implementations.
//** Usage
//Create an array with capacity 2
CArray * array = CArrayInit(2);
//Add two buckets
CArrayAdd(array, "test");
CArrayAdd(array, "another test");
//Add another and it will resize accordingly
CArrayAdd(array, "yet another");
//Print All
for (int ii = 0; ii < array->count; ++ii)
{
const char * buffer = CArrayObjectAtIndex(array, ii);
printf("Index: %d - %s\n", ii, buffer);
}
Download:
CArray.h
CArray.c
Notes:
The following test function usually reports about 5x faster than NSMutableArray which I think is a credit to how efficient the Objective C library and messaging system really is considering all the things your missing out on (exceptions, null pointers etc)
void CArrayTestRoutine()
{
CArray * array = CArrayInit(0);
NSTimeInterval start = [[NSDate date] timeIntervalSince1970];
NSString * test;
for (int ii = 0; ii < 10000000; ++ii)
{
CArrayAdd(array, @"test");
test = CArrayObjectAtIndex(array, CArrayCount(array)-1);
}
CArrayRemoveObjectAtIndex(array, 0);
NSTimeInterval end = [[NSDate date] timeIntervalSince1970];
printf("CArray 100,000,000 Elements took %fs\n", end-start);
NSMutableArray * nsarray = [[NSMutableArray alloc] initWithCapacity:0];
start = [[NSDate date] timeIntervalSince1970];
NSString * string;
for (int ii = 0; ii < 10000000; ++ii)
{
[nsarray addObject:@"test"];
string = [nsarray objectAtIndex:[nsarray count]-1];
}
[nsarray removeObjectAtIndex:0];
end = [[NSDate date] timeIntervalSince1970];
[nsarray release];
printf("NSMutableArray 100,000,000 Elements took %fs\n", end-start);
printf("%s\n", [string UTF8String]);
printf("%s\n", [test UTF8String]);
CArrayDestroy(array);
}