iPhone Development

I have recently been questing heavily to get up to speed with my iPhone development. I've learnt a lot and I owe much of my knowledge to others. Now I can safely say I'm 'getting there' with my abilities on the device I'd like to share some of my knowledge with anyone who is interested.

I'll be covering anything relevant to either cocoa, os x dev and iPhone dev. Thanks to the NDA being lifted I can now do so without issue so here goes.

Drupal blog App

I used the wordpress blogging app for the iPhone a few months ago and decided that I'd love one for drupal. So far I haven't found one so unless anyone else does one in the next month or so I'll start work on one. I need to plan the feature set before diving into code so if you stumble by this page and have suggestions, please leave a comment or use the site contact form to put forward your ideas.

NSXMLNode children by name

I needed to parse some xml recently and found a neat little category to add to the NSXMLNode class. Basically this allows you to find a node by name.

@implementation NSXMLNode (utils)

- (NSXMLNode *)childNamed:(NSString *)strName {
NSEnumerator *e = [[self children] objectEnumerator];

NSXMLNode *node;
while (node = [e nextObject])
if ([[node name] isEqualToString:strName])
return node;
   
return nil;
}

- (NSArray *)childrenAsStrings {
NSMutableArray *ret = [[NSMutableArray arrayWithCapacity:
[[self children] count]] retain];
NSEnumerator *e = [[self children] objectEnumerator];
NSXMLNode *node;
while (node = [e nextObject])
[ret addObject:[node stringValue]];

return [ret autorelease];
}

@end

Don't forget to add the interface to go with it. Than you can run a simple:
[someXMLnode childNamed:@"anotherNode"];

SOAP requests with Cocoa

I'm just trying to send some xml data to a soap server. While I may not have found the 'correct' way of doing it, I did find some information on sending data within the Apple documentation.

NSData *XMLdata = [soapXML XMLDataWithOptions:NSXMLNodePrettyPrint];
NSURL *webserviceURL = [NSURL URLWithString:@"http://soap.example.com/soap.php"];
NSMutableURLRequest *URLrequest = [NSMutableURLRequest requestWithURL:webserviceURL];
[URLrequest setHTTPMethod:@"POST"];
[URLrequest setValue:@"text/xml" forHTTPHeaderField:@"Content-type"];
[URLrequest setValue:@"http://soap.example.com/soap.php/login" forHTTPHeaderField:@"Soapaction"];
[URLrequest setHTTPBody: XMLdata];

NSURLConnection *connectionResponse = [[NSURLConnection alloc] initWithRequest:URLrequest delegate:self];
if(!connectionResponse) {
NSLog(@"Failed to submit request");
} else {
NSLog(@"Request submitted");
receivedData = [[NSMutableData data] retain];
}

As you can see we are creating some POST data and sending an NSData object across. I'm building up the SOAP envelope by loading up the basic envelope structure from a file then adding the correct data using the NSXMLDocument classes.

NSXMLDocument *soapXML = [[NSXMLDocument alloc] initWithContentsOfURL:[NSURL fileURLWithPath:envelopePath] options:NSXMLDocumentTidyXML error:&error];

Then we add the extra nodes:

NSXMLElement *rootElement = [soapXML rootElement];
NSXMLElement *soapBody = [NSXMLElement elementWithName:@"SOAP-ENV:Body"];

// Now create the actual login block of the envelope
NSXMLElement *loginNode = [NSXMLElement elementWithName:@"m:login"];
NSDictionary *loginAttribs = [NSDictionary dictionaryWithObjectsAndKeys:serverURL, @"xmlns:m", nil];
[loginNode setAttributesAsDictionary:loginAttribs];

[soapBody addChild:loginNode];
[rootElement addChild:soapBody];

Now you can use the NSURLConnection correctly.

Because we are using a delegate of 'self' we'll need to implement the relevant methods to cope with the data as it comes in. For that, I'd say read this document and familiarise yourself with the callbacks: http://developer.apple.com/documentation/Cocoa/Conceptual/URLLoadingSyst...

XML parsing on iPhone

I was working with yet more XML the other day and found out after almost completing my testing in the simulator that NSXMLDocument and support classes are not included on the device. This is apparently because they are a little too heavyweight for the device. I find that odd given that we can deploy complex 3D games on the same platform yet XML isn't quite ready. Anyway, there's a couple of alternatives. We have access to the libxml2 libraries which would need to be included in the build if used. There's a library in google code for TouchXML which should help with this. Then there's the included XMLParser which works as an event based parser reading through the tree. I suppose the third option (even though I only said a couple) would be to use CFPropertyListWriteToStream which should sort out some woes too.

UPDATE: All sorts of stuff has changed for OS 3.0 so I will get around to updating this page asap.

base64 Encode

I'm writing a small export plugin for Apple's Aperture. While the sample FTP plugin does the job mostly, I needed something a little more feature rich for a web image gallery we have.

I started off by adding a receipt file to go alongside the image which included all the meta data to help categorise the image on the website. This worked reasonably well, along with a cron job to read the receipts and move the files.

Considering I want to allow others to use this plugin and that each person would need a unique login, I decided to use a SOAP based solution to get around the problem. The one huge caveat was, I needed to send binary data. I'm not up to speed with the SOAP with Attachments protocol so the only real solution for me was to base64 encode the data. Cocoa and objective C do not have this as a buillt-in method but I found a solution.

I found a lovely set of category classes by Dave Dribin to add that functionality to NSData. His website is: http://www.dribin.org/dave/ and the link to the blog item on the encoder is: http://www.dribin.org/dave/blog/archives/2006/03/12/base64_cocoa/