Creating NSDocument using Folder Bundles and UTI Identifiers

I've been working on a Lion NSDocument-based application that deals with multiple data files. I decided to work with the NSFileWrapper and treat a folder like a single file. (i.e. Xcode Project Files .xcodeproj) I wanted to get an icon to display for the folder and to have it appear as a  single file on Finder. In the NSDocument you need to implement the two save/load methods to get started and then you need to edit your Info.plist file.

- (NSFileWrapper *)fileWrapperOfType:(NSString *)typeName
                               error:(NSError *__autoreleasing *)outError {
    // Save data here ...
}

- (BOOL)readFromFileWrapper:(NSFileWrapper *)fileWrapper
                     ofType:(NSString *)typeName
                      error:(NSError *__autoreleasing *)outError {
    // Load data here ...
}

Problems

There's a few gotchas with the .plist file. In order to create a NSDocument using Folder Bundles you'll need to set the UTI Identifier for the Document  Type and the Exported/Imported UTIs. You'll find this setting on the Info page for your Xcode Target.

 

  1. My App doesn't load saved bundles (NSFileWrapper), instead it just looks inside the folder.Can t Load Data
  2. I tried to undo the Export UTI by deleting it and remove the Identifier, but that doesn't help.
  3. By deleting the Identifier I can't load "New documents".

Solutions

There are two solutions, the second one is more robust, but the first will get you back to when it was working.

Solution 1: Revert back to Xcode template defaults

  1. Remove all Exported UTIs
  2. Open your App .plist file and remove the LSItemContentTypes from your App .plist file. You can't see it in the Target -> Info page.
    1. NOTE: if you don't delete an empty LSItemContentTypes array, then you won't be able to open New files.
    2. If LSITemContentTypes is defined, it'll ignore the "Bundle" checkbox (LSTypeIsPackage) See the Apple docs.
  3. Make sure "Bundle" is checked on the Document Types on your Target's Info page, or (LSTypeIsPackage on .plist file)
    1. This option is magic and auto generates a Identifier for you. (check your save file with "mdls" on the Terminal)
  4. Don't use an Identifier if you check the Bundle option (Document is distributed as a bundle)
  5. Clean the Xcode project

 

Solution 2: Use the package UTI

You'll need to add the correct LSItemContentTypes found in Apple's documentation. I took a look at the Xcode project file with the Terminal utility "mdls" (See sample output below)

  1. Set a unique identifier (Reverse DNS name) com.Your_Company_Name.Project_Name
    1. It needs to match theDocument Type and Exported UTIs
  2. For a bundle, you'll need to set the "Conforms To" for the Exported UTIs to "com.apple.package"
    1. Apple Docs: "A package (that is, a directory presented to the user as a file)"
  3. I noticed Xcode project files also include, public.composite-content
    1. Apple Docs:  "Base type for mixed content. For example, a PDF file contains both text and special formatting data"
  4. NOTE: If you mistype com.apple.package, or leave it out, your file folder will be treated like a public.folder, and you'll get folder behavior.
  5. Clean the Xcode project

Com apple package

Working Icon and Bundle File

If all goes well you'll now see the Icon (icns) file that you created in the Open dialog and the folder will appear to be a bundle.

OpenDialogWorks

Using MDLS to inspect your files

The only way it works as a bundle is if the "com.apple.package" ContentType is listed, otherwise something is wrong. Check your save files with the "mdls" command.

mdls MathAndArt.xcodeproj/

Screen Shot 2012 02 02 at 7 57 23 PM