ChariotNews

This category will feed the Chariot Solutions blog site.

US Mobile Browser Stats

I found these stats from StatCounter interesting. If you are planning or implementing a mobile web app focused mainly at the US, you can cover 83% of the native mobile browser market by developing for and testing on Android and Mobile Safari. Of course, you need to consider variances between OS versions, etc. ūüôā

Advertisements

NSFetchedResultsController and Core Data Managed Object Updates

In the process of working on an iPhone project for a client, I came across an interesting problem. I was using Core Data to store domain related information. This data is being pulled from a server, parsed, and persisted on a background thread. The main thread of the application presents a list of information based on what is persisted. In this application, I chose to use an NSFetchedResultsController to manage querying the underlying Core Data store and implemented the standard UITableView delegate methods. I won’t go into detail on how to do that here, but there are many good write-ups out there, including this very good one: How to use NSFetchedResultsController.

I was updating the underlying data store in a background thread with its own managed object context, as is the standard practice. As a result, the NSFetchedResultsController’s managed object context was unaware of the changes to the data store. This was easily fixed by subscribing to the NSManagedObjectContextDidSaveNotification notification in my table view controller class.

[[NSNotificationCenter defaultCenter] addObserver:self 
                                         selector:@selector(refreshData:) 
                                             name:NSManagedObjectContextDidSaveNotification 
                                           object:nil];

The notification that gets fired includes all the information about the changes to the underlying data store (Inserts, Updates, and Deletes). The nice thing here is that there is a convenience method on the managed object context for merging these changes in, as shown in the snippet below:

- (void) refreshData:(NSNotification *)notif {
    [[[self fetchedResultsController] managedObjectContext] mergeChangesFromContextDidSaveNotification:notif];
}

On the surface, this worked beautifully. Once the changes are merged in, the NSFetchedResultsController delegate methods start firing. This is where my struggle occurred. All the proper delegate methods fired correctly, but the underlying result set for the NSFetchedResultsController still had the old data. I combed through the documentation, code samples, etc. and it seemed that I was doing everything correct. I came up with some hack arounds, but they were too ugly…and just wrong. I knew there had to be something I was missing.

I could see that the object that I updated in my main thread’s managed object context was a faulted object (see Apple’s description of a Faulted object here if you aren’t familiar with this concept). What I didn’t realize is that when accessing attributes of a faulted object, the store will retrieve the underlying data from the previously fetched data first, then from the underlying data store. How long the previously fetched data is used is based off of the staleness interval attribute of the managed object context. BTW, this defaults to infinity ūüôā

So, the addition of 1 line of code when creating my NSFetchedResultsController to set the staleness time interval to 0 fixed everything.

[context setStalenessInterval:0];

Now my NSFetchedResultsController delegate methods were able to update the table view with the updated data as expected.

For those of you following the tutorial referenced above, one change is necessary if you use a sectioned table view by setting the sectionNameKeyPath when initializing the NSFetchedResultsController.

In the didChangeObject delegate method, the NSFetchedResultsChangeMove case should look like this:

case NSFetchedResultsChangeMove:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] 
                             withRowAnimation:UITableViewRowAnimationFade];
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] 
                             withRowAnimation:UITableViewRowAnimationFade];
            break;

Otherwise you will get an error under certain use cases (e.g. changing/removing the last item in a section so the section gets deleted).

Trying out Adobe Flex for Mobile Development

Let me start by saying I have never developed using Flex or any Adobe tools.

I’ve heard a lot of mentions of Adobe’s tools for Android and iOS development and decided to give them a try. The first thing I thought I needed to do was download some tools and SDKs. Was it Flash, Flex, Flash Builder for making Flex apps, AIR…..Adobe doesn’t make it easy. In the end, I found a nice step-by-step tutorial here: http://www.adobe.com/devnet/flex/articles/twitter-trends.html.

Tools
Turns out I needed Flash Builder 4.5, which allows you to develop Flex apps, and somehow AIR fits in here….beyond breathing of course. Actually, it provides the runtime for Android and ends up being packaged as part of the iOS app, acting as “captive runtime” (according to Adobe docs). I guess if you are familiar with Adobe tools, this is all obvious….but as I mentioned, my background is mobile development, not flex/flash development.

It was time to install the IDE. Flash Builder 4.5 is based on Eclipse….OK, maybe I can install an Eclipse plug-in instead. Turns out they do have an Eclipse plug-in, but you have to install their full version of Eclipse first, then you can install the plug-in into your version of Eclipse….WHAT?. So I downloaded a trial version of Flash Builder and installed it.

Following the Tutorial
The tutorial was well written and easy to follow. The only correction needed was the trends URL for twitter, which is this: http://api.twitter.com/trends.json. There is a lot of clicking and code templates that come into play…and I am certainly no fan of coding in XML….I kind of feel dirty doing it. But the tools do provide some nice abstractions, like making it really easy to connect to an HTTP service and make REST calls and handle JSON or XML. They also have a pseudo emulator that you can use during development. It is incredibly basic, but you can do things like simulate rotation, let it act like different OS’s….but it really just looks like a headless browser window.

Next up, the part of the tutorial where you get to deploy the app to an actual device. This is the part I was waiting for. How would it perform? Can I debug? How does it work on iOS? All these questions were ready to be answered.

Running/Debugging
Running and debugging on an Android device was simple and worked fine. It was a different story for iOS. First you had to get your developer certificate in p12 format….hopefully you remember your password, if not you will need to re-export it from keychain. You also need you provisioning profile. Once you get this configured, you have to build the app for iOS, copy it into iTunes, sync your device so the app gets loaded, then run the app. Debugging involves all these steps, plus your development machine needs to be on the same network as your device and debugging occurs over WiFi. Really. And every time you make a change….delete the app from the device, rinse, and repeat. Really, really. It took me several IDE restarts and iOS device disconnect/reconnect cycles to get the debugging to actually work….but once it did…(insert sarcasm) well, it worked (end sarcasm).

Conclusion
On the devices, the app didn’t really perform that well. Scrolling was bit jerky and transitions seemed slow. Oh, and the tutorial neglected to give you a back button for iOS devices to be able to pop the view off the navigation stack. I’ll post a little work around/additional code for that separately.

In the end, the tools are OK. The language (MXML/ActionScript) is not my cup of tea. The performance on the devices was really mediocre. Not being a Flex developer, I am not sure if that can be improved…it was only a tutorial. I think for simple apps, this might be an alternative. If you are a Flex developer, this is definitely and option to allow you to create mobile applications. Will I use it, doubtful. I’ll stick to either native app or mobile web development.

Executing JavaScript from Objective-C in an iOS App

The other day, I found the need to execute some JavaScript from a native iOS application.  After doing a little research, I discovered that the UIWebView has a stringByEvaluatingJavaScriptFromString method.  So I decided to create a quick little proof-of-concept to see how to invoke some JavaScript using this. I am not going to walk through all the details of creating a project, etc. and will cut right to the important aspects of making the JavaScript call from the objective-c code.

We are going to need a JavaScript function to call and a UIWebView to evaluate the JavaScript. It would be nice if the JavaScript function took a parameter as well, so we could also prove out the passing of values.  Here is the JavaScript function that I will use:

var area = function(diameter) {
     var radius = diameter/2,
     area = Math.PI * radius * radius;
     return Math.round(area*100)/100;
};

Next we need to load this JavaScript in a UIWebView to allow for the call to stringByEvaluatingJavaScriptFromString. This can be done several ways. One option is to embed JavaScript in a dummy html file and load that into the UIWebView. You could also load an externalized JS file into the dummy html file. I chose to load some inline html into the UIWebView that included a reference to the externalized JS file. This way I don’t need any extraneous files hanging around. Also, I wanted the JS to live in its own file and act as a library I could use in other (non-objective-c) applications, so I placed it in the calc.js file. Here is the code to load the JS file into the UIWebView:

[webView loadHTMLString:@"<script src=\"calc.js\"></script>" 
              baseURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] resourcePath]]];

Here is the code to make the JS call:

NSString *function = [[NSString alloc] initWithFormat: @"area(%i)", diameter];
NSString *result = [webView stringByEvaluatingJavaScriptFromString:function];

Now, there is one important safety tip to make this actually work: The UIWebView must actually be loaded a view. It doesn’t have to be visible, but in order for the WebKit engine to execute the JS, it must be on a view.

Also, when you perform a build, you will get the following warning:

no rule to process file ‘$(PROJECT_DIR)/Classes/calc.js’ of type sourcecode.javascript for architecture i386

This can be eliminated by moving the calc.js file from the Compile Sources Task to the Copy Bundle Resources task within your project target. It should look something like the image below.

Project Pane - Target

That should do it. Once all these pieces are in place, you will have objective-c executing JavaScript.

The source code can be found on github here.

Please forgive the UI (and the lack of memory mgmt), as I just threw this together ūüôā

Basic Mobile Device Detection

These days, there are many ways to browse the internet.  There are desktop browsers, mobile phone browsers, tablets, tablet/phones (e.g. Dell Streak), etc. all with different screen sizes, resolution, and capabilities.  How do you render an appropriate view optimized for the device accessing your site?  The answer is device detection.

The two main approaches for device detection are server-side detection and client side detection.  Server side detection involves determining the device at the time of the request and then presenting the appropriate view.  Client side detection involves manipulating the view after the content has been sent to the browser.

Client side approaches include: feature detection via JavaScript, CSS media types, and CSS media queries.  This approach, while simpler, is subject to the capabilities of the rendering browser.  Some browsers have little or no support for JavaScript, while others only support older CSS standards.  With the myriad of devices and their associated browsers, this can be a significant challenge.

When it comes to server-side detection, the main approach is to rely on the USER_AGENT (UA) HTTP header string that comes in each web request.  There are many frameworks and tools to help interpret the UA string, and I will present some of those options in a subsequent blog post.  For now, it is a safe assumption that classifications of devices (e.g smart phone, feature phone, etc.) can be determined via the UA string.

There are many ways to use one or both of these approaches.  As always, it depends upon your requirements.  Many times, a simple approach will work best.  WebKit based browsers, such as those found on iOS, Android, and some Blackberry devices, are the most capable mobile browsers today.  These devices have excellent support for JavaScript and CSS.  It may be perfectly acceptable to focus on devices with these browsers and render a touch based, optimized experience for those requests, while presenting a basic HTML only view for any other mobile devices.  Using server-side detection, the browser type can be determined and the appropriate content can be sent to the browser for rendering.

Is that enough? ¬†Today’s mobile landscape is rapidly changing, with new phones and tablets coming out each month. ¬†All these devices have different screen sizes, resolutions, etc. ¬†Is one mobile touch based user interface design enough? ¬†Would the same view be appropriate on a 3.5 inch iPhone screen as a Galaxy Tab 7 inch screen? ¬†What about a 9.7 inch iPad screen? ¬†Probably not. ¬†This is where client side detection can come in handy. ¬†Through the use of CSS and JavaScript, content can be altered, adapted, and enhanced to take advantage of the larger screens when appropriate.

While this combination of server and client side detection may not be appropriate for your circumstances, it is a simple approach that is valid for many situations.