I was working on an application a while back which required file references to be stored by Core Data. These references needed to be fairly robust. If the user decided to move a file for example, the application needed to be able to locate that file in its new location. The answer was to use aliases, but as it took a bit of digging to work out how to do this I thought it would be worth sharing.
I think the easiest way to explain this is to walk through an example. However, if you want to skip the tutorial you can download the example project here. Please feel free to reuse any of this code (although I provide it with no warranty). If you do use it, or if you find this post useful, I would be love to hear from you - it’s nice to know you might have helped someone.
For the example I’m going to create a simple Core Data application with a table view displaying the full file paths of various files. To do this I need to represent the path in two ways; an alias to the file and a string containing the path. Only the alias will be stored by Core Data.
To start, create a new project in Xcode using the Core Data Application template. I’ve called my project FileRefs - inspired naming I’m sure you’ll agree.
In the data model file (FileRefs_DataModel.xcdatamodel) create a new entity. Set the name of this entity to FileData and the class to OPSFileData (we’ll create this class in a moment). Next, add a new attribute named aliasHandle to the entity. This attribute is going to store the file alias in the form of an NSData* object, so we set the type to Binary data. If a file is removed, or an invalid file path is entered, then this NSData* object will be nil, so we need to set the optional flag.
Add a new class named OPSFileData to the project derived from NSManagedObject and add the following properties:
@property (retain) NSData* aliasHandle;
@property (copy) NSString* filePath;
You will also need to include the definition for NSManagedObject:
The aliasHandle property is already in the data model so we declare it using a dynamic property:@dynamic aliasHandle;The filePath property will return the string representation of the file path for display in the table view. The OPSFileData class will implement the accessors for this property. The ‘get’ method will convert the aliasHandle into a string while the ‘set’ method will convert a string into an aliasHandle. Add these methods to the implementation as follows:- (NSString*) filePath
- (void) setFilePath:(NSString*)filePathAsString
The final thing to do is to hook up the user interface. Open the XIB file and add a new NSArrayController named FileData Array. In the inspector window for the array controller’s bindings, bind the Managed Object Context to the app delegate (FileRefs_AppDelegate). This will tell the array controller where to look for the managed object context. Switch to the attributes tab for the array controller and set the object controller’s mode to Entity. The entity name is FileData - this is the name of the entity we created earlier in the data model. Finally, set the Prepares Content check box to tell the array to load the data at start-up.Add a NSTableView to the application window, turning off the headers and setting the number of columns to 1. In the binding for the table column (make sure you select the table column and not the view) bind the value to FileData Array. The controller key should be set to arrangedObjects and the model key path to filePath. This tells the table column that its contents will be provided by FileData Array’s arrangedObjects property and that each of the objects in this array has a filePath property.
Add two buttons to the window: Add and Remove. Control click on the Add button and drag to the FileData Array object to connect the button to the controller’s ‘add’ method. Similarly connect the Remove button to the controller’s ‘remove’ method.
You should now be able to build and run the application. Add a new item and type in the path to a file on your machine. Move this file and you should see this path updating as you switch focus back to your application.
That’s it. The user interface needs a little more work; the button states should be bound to the ‘canAdd’ and ‘canRemove’ methods on the array controller. And of course you’ll have taken Martin Pilkington’s pledge and will be making your app accessible.
2 Comments:
Doesn't seem to work in snow leopard... The table (cell) doesn't become editable.
Hm.
Actually, I think an update to this article is needed. This file reference code works fine until you want to use undo (Daniel explains it nicely http://danielkennett.org/?p=450).
We have a solution, slightly different to Daniels, which I want to write up and share. However, at the moment we're struggling to find time to complete our new app whilst doing client work as well - so I'm not promising it'll be anytime soon.
Get in touch if you'd find it useful to have this new code though and I'd be happy to send what we have.
Post a Comment