Posts Tagged ‘objective-c’

Rantings and failures about unit testing iPhone apps

Apple Headquarters

I’ve been trying to write unit tests for any iPhone apps that I write. With Xcode, that’s much much easier said than done (it should not be this difficult!).

I’ve tired a couple of frameworks and tried to follow several steps found on Google. So far nothing is doing the trick.

My latest effort followed instructions for using OCUnit written by Sen:te. After following the steps outlined, I get this error when compiling and running the project:

error: Testing rig /Somepath/iPhoneSDKVersion/otest exited abnormally with code 139 (it may have crashed).

Naturally I turned to trusty Google which came up with nothing helpful.

Thinking that it was a failure to follow the directions, I downloaded the sample test application, loaded the project in Xcode, then built and ran the project. Same error.

I tweeted to Michael Galpin, a programmer at eBay, asking for any ideas on unit testing iPhone apps. Since he had just given two presentations on mobile development [1, 2] for the Silicon Valley Code Camp 09, I thought he might have some ideas.

His initial response does not give me good feelings about iPhone development:

I’ve only seen homebrewed stuff. XCode is not exactly extensible.

He did turn me to the google-toolbox-for-mac which has some promising instructions on doing iPhone unit testing.

Using Xcode feels something like this...

Using Xcode feels something like this...

What bothers me about doing iPhone development is that I am leaving all my very excellent development tools for iffy tools.

Sun wants Java on the iPhone and is willing to make it happen. Java has one hell of a community behind it and Apple could really benefit from it.

Unfortunately someone at Apple has some bad information on Java.

Perhaps Apple is just interested in keeping it’s pet language alive and kicking. After all, Apple seems to have problems with Not Invented Here.

This was not really meant to turn this into a bit of an Apple hate-fest. It’s just that the tools and community that Java has is light years ahead of what Apple is offering anyone interested in iPhone app development.

When I’m effectively boxed into Xcode to do iPhone development, that’s a problem. I would like an IDE that doesn’t seem to break at least one thing every update. Chris Hanson’s steps to setting up unit tests has required updating between various Xcode updates.

More importantly, the barrier to entry for unit testing iPhone apps is painfully high. I have almost given up and I’m already sold on the idea of unit testing. Imagine if I wasn’t already sold.

google-toolbox-for-mac is next up for me to try. Wish me luck, I’ll need it.

 

Compiling MGTwitterEngine for the iPhone using Xcode

Surprisingly there are not a lot of options for Objective-C Twitter libraries. In fact there are exactly two options: MGTwitterEngine and Canary (which is actually a “full-fledged client”). The choice looks clear, use MGTwitterEngine or deal with XML directly (yuck!).

MGTwitterEngine does not implement the entire Twitter API but it does implement the most important things like updating status, retrieving your friend’s timeline, etc. For my current uses, that’s all I need.

It took me a little bit of effort to get MGTwitterEngine compiling and running correctly:

  1. Checkout the project from subversion (svn co http://svn.cocoasourcecode.com/MGTwitterEngine-1.0.8/).
  2. Delete files that aren’t needed: .svn, AppController.h, AppController.m, English.lproj, Info.plist, main.m. Optionally delete README.txt, TODO. Leave alone Source Code License.rtf.
  3. Add the remaining sources to your project.
  4. Change USE_LIBXML to 1 (instead of 0) to use libxml for a smaller footprint.
  5. In your target, within the general tab add libxml2.dylib.
  6. In your target, within the build tab, add to “header search path”: “${SDKROOT}/usr/include/libxml2″. Make sure you’ve selected the recursive checkbox.

If you are getting an error saying “error: libxml/xmlreader.h: No such file or directory”, make sure you’ve completed the last 2 steps listed above.

A working example can be found on an early commit to my iPhone app hosted on github.

 

Saving app data with the iPhone SDK and Cocoa is easy with NSUserDefaults

A quick look at NSUserDefaults suggests saving app data with Cocoa and the iPhone SDK is easy. I haven’t gotten much of a chance to use it so there might be some gotchas.

To store nonsensitive data using NSUserDefaults is as easy as a couple of lines of code:

[objc]
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:usernameTextField.text forKey:@"username"];
[defaults synchronize];
[/objc]

The last line is particularly important as it actually saves the data to disk.

Retrieving data is equally as easy:

[objc]
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSLog([defaults objectForKey:@"username"]);
[/objc]

NOTE: Using NSUserDefaults is a really bad idea for sensitive data like passwords. A significantly safer solution would be to use the iPhone’s keychain. Apple has an example found in GenericKeychain.

The API can be difficult to understand and cumbersome to use. Luckily, there is a solution for that from Buzz Anderson and it can be found on github.

 

How to: HTTP POST and Google’s ClientLogin using Objective-C and the iPhone SDK

PLEASE NOTE (2009-08-12): You probably do not want to use this method (though it’s great for learning). A much better solution is to use the gdata-objectivec-client. Example code on using that library can be found in one of my projects hosted on github.

I’ve been working on an iPhone app that uses one of Google’s APIs.  The following appears to work just fine in a non-jailbroke phone.

Creating the request

[objc]

NSURL *url = [NSURL URLWithString:@"https://www.google.com/accounts/ClientLogin"];

NSMutableURLRequest *loginRequest = [NSMutableURLRequest requestWithURL:url];

[loginRequest setHTTPMethod:@"POST"];</code>

//set headers

[loginRequest addValue:@"Content-Type" forHTTPHeaderField:@"application/x-www-form-urlencoded"];

[loginRequest addValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];

NSString *requestBody = [[NSString alloc]

initWithFormat:@"Email=%@&amp;Passwd=%@&amp;service=finance&amp;source=%@",

username, password, [NSString stringWithFormat:@"%@%d", @"ashlux-igFinance-1.0"]];

[loginRequest setHTTPBody:[requestBody dataUsingEncoding:NSASCIIStringEncoding]];

[/objc]

This part is fairly straight-forward. The service=finance should be changed to the Google service you are using.  Also ashlux-igFinance-1.0 should be changed to the format company-appname-version.

The default timeout interval for the request connection is 60 seconds.  To change this, use setTimeoutInterval:

[objc]

[loginRequest setTimeoutInterval:30]; // set timeout for 30 seconds

[loginRequest setTimeoutInterval:90]; // set timeout for 90 seconds

[/objc]

Sending the request

To send the request, I am sending a synchronous request (which will block) to Google:

[objc]

NSHTTPURLResponse *response = NULL;

NSData *responseData = [NSURLConnection sendSynchronousRequest:loginRequest returningResponse:&amp;response error:nil];

NSString *responseDataString = [[NSString alloc] initWithData:responseData encoding:NSASCIIStringEncoding];

NSLog(@"Response from Google: %@", responseDataString);

[/objc]

Objective-C does have asynchronous IO (non-blocking), but that’s for another time.  For most purposes, asynchronous is the way to go to avoid blocking the application.

Reading the response

For my purposes, I am storing the data in a struct called GoogleClientLogin to represent Google’s ClientLogin data (that’s simple enough, so I will not list it here).  For simplicity, I am not interpreting the response status beyond success (code=200) and failure (code=anything else).

[objc]

if ([response statusCode] == 200) {

NSLog(@"Login successful.");

GoogleClientLogin *aGoogleClientLogin = [GoogleClientLogin alloc];

aGoogleClientLogin.username = username;

aGoogleClientLogin.password = password;

NSString *authToken = [[responseDataString componentsSeparatedByString:@"Auth="] objectAtIndex:1];

NSLog(@"Google authToken=%@", authToken);

aGoogleClientLogin.authToken = authToken;

return [aGoogleClientLogin autorelease];

} else {

NSLog(@"Login failed.");

return nil;

}

[/objc]

That is more or less all there is to it. There is room for better error handling, but the effort would be better spent elsewhere on the applcation.

Next up, I’ve really need to figure out how to work in unit tests using Xcode.  My previous attempts at getting OCUnit working were full of fail special thanks to Apple’s out-of-date documentation.

 

Unexpected error 0xE800003A application verification failed

I’ve been spending time lately learning to use Objective-C and the iPhone API.  While trying to deploy a sample iPhone app through Xcode, I ran into a pesky error message.

Your mobile device has encountered an unexpected error (0xE800003A) during the install.

Application verification failed.

Configuring Xcode is a quick and easy two step process (assuming you’ve setup the appropriate certificates, provisioning, etc. with Apple):

  1. Set your bundle identifier in Info.plist (This is your APP ID excluding the Bundle Seed ID).
  2. Set the project code signing identity to your provisioning profile.

That’s it!

Of course, I ran into three different errors when trying to deploy it to my iPhone:

  1. Bundle identifier is incorrect (typo or bundle seed ID was included).
  2. Incorrect provisioning profile was selected.
  3. Clean and rebuild and deploy (Build > Clean All Targets).

The first two problems where easy to resolve, but the third item was definitely tricky.  Who would have thought you’d need to clean the project after making that sort of change?