Here’s another good tutorial at MobileOrchard — my, they are on a run lately, aren’t they? — Lite To Paid iPhone Application Data Migrations With Custom URL Handlers.
Apple enforces a number of restrictions on applications in the App Store. Among the most painful is the lack of feature-limited trials. Applications are either completely free, or the customer must pay up front, sight unseen. The proliferation of “Lite” applications is a direct result of this shortcoming…
When building a game or other stateless application the approach makes complete sense. However, utility applications often maintain information entered by the device owner. Application authors are faced with a dilemma because the iPhone’s security sandbox prevents one application from reading another application’s files. Thus, when customers upgrade from the Lite application they are penalized by having to re-enter all data!
This is rather apropos, as we’ve been already planning something along these lines for migrating data from paid for 2.0 applications to new StoreKit-using 3.o applications, which is more or less the same basic problem as the Lite-to-Pro style migration they have in mind.
The tutorial goes on into exhaustive detail, but the basic idea is to use URL handlers for IPC between your application versions as we’ve mentioned earlier. We do have one additional tip to add though; they focus on using solely the URL itself to transfer data, which there’s a good chance to be problems with using for data in the dozens of megabytes like we need to do. Luckily, we have another earlier post of ours to point you at what looks like a fruitful avenue of inquiry; figure out where UIImagePickerController writes its photographs, which it seems is and is likely to continue to be necessarily a shared access folder, and stick your large temporary data in there. We’ll let you know how that works out once we’ve tried it!

> figure out where UIImagePickerController writes its photographs, which it seems is and is likely to continue to be necessarily a shared access folder, and stick your large temporary data in there. We’ll let you know how that works out once we’ve tried it!
That’s a really cool idea, keep us all posted!
With regard to the reliability of sending large amounts of data over the URL handlers, I haven’t heard of any issues yet, but if you do end up giving it a shot I’d be curious to hear about how it fares with largish data sets.
Why not put the information on the pasteboard in a custom type? On the launch of your new program examine the pasteboard and automatically load the data if its’ available and/or needed, during first launch only maybe?
@Ashley:
Because the information is larger than the memory installed in the device, so putting it on the pasteboard would appear to be fraught with peril. At best.
@Alex:
Just ran a few tests here, a custom UIPasteboard created with pasteboardWithName:create: and set to persistent stores its’ data across a reboot of the phone itself. It therefore must not be keeping all of that data in memory.
I think there may be more smarts in that class depending on the size of the content placed on it than just storing it in the working memory of a server process.
@Ashley:
Huh. Well, if that works for 100 meg, that would definitely be the way to go then. Thanks for the update!
@Alex:
How did it work out ? Was the UIPasteboard able to handle 100 MB ?
Haven’t got around to it yet — still waiting for a final 3.1 SDK before we have something to be sending it to…
having a problem with pasteboard persistence. i create a custom pasteboard with a unique name and set its persistent property to YES, but upon quitting and restarting the app or on quitting and launching another app the pasteboard is not found. any ideas? thanks
First off I’d try using the general pasteboard instead of a custom pasteboard. That’ll narrow it down to either your pasteboard handling or your data handling, which is a start.
Thank you for your prompt reply, Alex.
When I use the general pasteboard the data appears to be saved and retrieved successfully. So it looks to be an issue with the custom pasteboard handling. Anything special I should do with the pasteboard beyond creating it and setting the persistent property? Also, how undesirable would it be to use the general pasteboard instead of a custom one for passing application-specific data (using a custom type) between two apps? Thanks again for your help.
Here is my code for creating the custom pasteboard:
UIPasteboard *myPasteboard = [UIPasteboard pasteboardWithName:GTKPasteBoard create:YES];
myPasteboard.persistent = YES;
GTKPasteBoard is a #define.
I’d be guessing it’s your name then. Sure you #defined an Objective-C string @”name” and not a C string “name”? Usually that kind of thing crashes in short order, but sometimes it just fails silently.
Good way to check that (or if there’s some other problem with your name) would be to use the -pasteboardWithUniqueName: call, get its name, mark it persistent, and see if that works.
If that doesn’t produce any enlightenment I’d just skip past the problem and use the general pasteboard since it works and worry about this for 1.1 if the app becomes a hit. There’s no particular downside to doing that besides other applications can mess with the data, which in most circumstances probably isn’t a showstopper concern.
Thanks again for your response, Alex. The #define is an Objective-C string, but maybe the system didn’t like it for some other reason. I’m for following your advice and using the general pasteboard, but I’ve got one question. Since the general pasteboard cannot be removed, and UIPasteBoard doesn’t seem to offer a method for removing objects, how do I get rid of the data I’m passing after I’ve retrieved it? Would setting it to nil do the trick?
To answer my own question, setting the value of the type to nil does seem to remove it.
Hi. I stumbled across this thread while researching a similar problem to Ilya’s, and have a bit more info. Although my App1 created a custom named pasteboard and put a string into it without issues, and it was definitely marked persistent, App2 couldn’t find that same pasteboard afterward. More testing finally revealed the problem: App1 of course used create:YES, but App2 was using create:NO to check for the data’s existence. For whatever reason, even if the pasteboard already exists, I had to pass create:YES on the second call to successfully find it to retrieve from it. create:NO always returns nil, whether the data has been saved or not. I know this thread is done, but maybe this will help some future Googlenaut like myself.