I don’t know how to access the filesystem on my iPhone from my desktop. I can write apps that talk to their sandboxed parts of the filesystem just fine, but I don’t know how to reach into arbitrary parts of the iPhone’s filesystem from my desktop and move files around. This can be inconvenient when developing and testing code. I have developed a workaround, however, which I’d like to talk about.
I have a SQLite persistent store for a Core Data application on my development device. This store has quite a bit of information in it, and I want to perform a complicated upgrade to a new version of the data model. The thing is, I’m not sure that I’m going to get it right the first time I do it. (In particular, I’m worried about performance – how long it will take to process the upgrade – that’s very tricky to gauge on the simulator.)
I want to copy the existing store to a safe location, try my upgrade, and then replace the original store if necessary. (And then repeat the process until I’m satisfied with the results.) Maybe everyone else in the world knows how to do this, but it’s Not Immediately Obvious To Me.
I can think of three basic approaches to this problem:
- Add a fileserver to my application (e.g. Cocoa HTTPServer), connect to it with a client (e.g. Safari) and manipulate my application’s files from the desktop
- Add a client of some sort (e.g. FTP) to my application, add a user interface to drive it, connect the client to a server, and manipulate my application’s files from within the application
- Jailbreak the device, install SSH/SFTP, and use those programs to run amuck over the filesystem
I don’t like any of these options.
It turns out that the GDB console is really powerful. You can execute, if not arbitrary, then at least quite general code from its command line. If there’s an
NSFileManager object in the current context, this means that you can move files around the application’s sandbox from within the debugger. This is a “good enough” solution for me, which has the primary virtue of being dead simple and quick to implement.
I added this line to my app’s
NSFileManager* fm = [NSFileManager defaultManager];
… and set a breakpoint right after it.
To copy my database, I issued these commands:
p (void) [fm changeCurrentDirectoryPath:[self applicationDocumentsDirectory]] p (int) [fm copyItemAtPath:@"TEST.sqlite" toPath:@"TEST2.sqlite" error:NULL]
applicationDocumentsDirectory method is a standard bit of Xcode Core Data boilerplate.)
You can see the effects with, e.g.:
po [fm directoryContentsAtPath:@"."]
<NSCFArray 0x3b06dd0>( TEST.sqlite, TEST2.sqlite )
Maybe there’s an easier way, but this works for me.