Sunday, September 7, 2014

Handling references to images in Xamarin iOS

I recently submitted a minor cosmetic update to an iOS app that I had created, and had a user report that after updating the app the app would crash on a certain screen (which was puzzling, given that it hadn't been affected by the update). I did some investigation and uncovered what is potentially a trap for app developers, so I thought I'd share it.

The app allowed users to take photos and would store them in the app's Documents directory (Environment.SpecialFolder.Personal in Xamarin) waiting to be uploaded to a web server. A SQLite database would maintain a reference to the full path of the documents directory and access that path when the time came to upload the image. The user in question had taken some photos and then updated the app before uploading them, which caused the app to crash. It turns out that when an iOS app is updated, the GUID of the path to the data directory for that app is changed and all of the existing files are moved there, meaning that the paths in the SQLite database were now invalid and caused a crash upon trying to access them.  This scenario, and the workaround for Objective-C apps is outlined on this Stack Overflow question.

Basically, the way to stop this from happening is to not store the full path to the file on disk, but instead store just the filename, and append it the Documents directory each time you access it. In Xamarin I did this via a helper class:



To illustrate it's usage, here is the code used to save the image:

var path = GetFullImagePath.ForFileName(imageFileName);
System.IO.File.Copy (t.Result.Path, path);

Then imageFileName is stored in SQLite, not 'path'.

If you implement this code you may not need the check to see if the path supplied is a full path, however it was necessary in my example because some of our users, including the one that reported the issue, will have the full path stored in the SQLite database - which will now call that helper method.

The moral of the story is: if you store a reference to files stored in your Documents directory in your iOS apps, make sure you don't store the full path or this will cause problems when your app is updated.