Sep 27

I am fortunate to be in a position to be selective about the clients I work with and the projects I work on. The project has to have some difficult technical challenge to satisfy the inner geek. But equally important is that the resulting app should do something good, something that helps people, and maybe make the world a little bit better.

An app that I recently completed fits these criteria perfectly. The app is called NutriSleuth and in a nutshell it allows people with allergies or other medical conditions to check out food items in the grocery store to see if they are going to make them, or anyone who they shop for, sick.

The app scans the bar code of a food item and uses the UPC to lookup the product in a database stored on the device. The database contains over 200,000 food items and over 2.5 million nutrition records. The database uses Core Data and its total size is over 500 MB on the device. Herein lies several technical challenges, and I’ll be writing a few blog posts about this.

Once the nutritional records for the product have been retrieved, a rules engine goes through the data to determine if the fits or clashes with the nutritional profiles the user has configured in the app. (This rules engine is part of the proprietary, secret sauce of this app, so unfortunately I cannot write about this in more detail.)

The result of the analysis is a simple green, yellow, red light that indicates if you can safely eat this food item, if you should exercise caution or put it back on the shelf immediately. Some people go into anaphylactic shock when they are exposed to certain food ingredients like peanuts, tree nuts, eggs, etc. This severity level can also be configured in the app and then the nutrition and ingredient analysis goes into hyper-vigilant mode.

The app does not just handle food allergies. Say that you have a friend who’s coming over for dinner and she has Crohn’s disease or a high cholesterol condition, or only eats vegetarian or only Kosher food. What can you safely serve for dinner? Setup a separate profile for you friend and scan away.

The app received a lot of press even before it was launched. I think the reason is that you instantly recognize that this app would be very helpful (potentially a lifesaver, literally) for so many people that have food allergies or other common medical conditions.

I’m proud to have been part of this project. And being able to do something really good like this, is one reason why I love being an iPhone developer.

You can check out NutriSleuth in the App Store now.

written by Nick \\ tags:

Mar 18

If your iPhone app needs to store or access a lot of data locally you should take a look at Core Data. It’s not a panacea, but I find that it’s particularly useful when you need to search a lot of data that may result in a very long list to present in a table view. For this use case the NSFetchedResultsController is your friend. It handles many of the nasty issues of memory management, ensuring that you have enough data in memory to populate the visible portion of the table view instead of loading the entire result set into memory at once.

Your code to perform a fetch using NSFetchedResultsController may look something like this:

NSPredicate *predicate =[NSPredicate predicateWithFormat:@"name contains[c] %@", searchText];
[self.fetchedResultsController.fetchRequest setPredicate:predicate];
NSError *error = nil;
[self.fetchedResultsController performFetch:&error];

If you’re using a UISearchDisplayController you may be tempted to call this code each time the user enters a new character in the search field. There may be obvious performance reasons why you cannot want to do this. If it takes a few seconds to perform each fetch after each character then it will make for very slow data entry that will frustrate the user.

But there’s a more subtle reason why this is a bad idea, which I recently ran into.

NSFetchedResultsController optionally caches results and the cache content may get out of sync if you just change the NSPredicate like the code above does. One way to get around this is to delete the cache before you set the new predicate:

[NSFetchedResultsController deleteCacheWithName:nil];
[self.fetchedResultsController.fetchRequest setPredicate:predicate];

I’ve seen the first code section in many Core Data code examples, but I’ve never seen anyone mention the need to delete the cache before you perform another fetch with a different predicate. Now it turns out that you don’t have to do this in the current iPhone SDK, because it “just happens to work” anyway. But this behavior may, or may not, change in an upcoming NDA-covered SDK release. Consider this an advance warning.

written by Nick \\ tags: , , ,