Sunday, October 11, 2009

NSURL to refer to a file path

I made a fairly simple Cocoa project (a checkbook application) that I would like to have its own icon. And specifically, I'd like to mark files so that the file system knows they belong to my app, are displayed with its icon, and launch the app when you double-click them. However, because it's so simple, this version of the project is not yet a document-based app.

Since my attempts haven't been fruitful so far, I decided to explore Launch Services, which the Finder uses to do these things. To do that, I need to make a file that I know I can load into my application. In this post, I show two ways to accomplish this very simple first step: one way is with an NString that is a path to the file, and one using NSURL. As the docs say: "NSURL objects can be used to refer to files, and are the preferred way to do so."

To make things simple, I am building and running from Terminal. The file is a text file containing "my data", with the .txt extension. Since its straight text, we can use either encoding as shown in the listing:

encoding:NSASCIIStringEncoding
encoding:NSUTF8StringEncoding


If you want garbage collection, see here.

As step 2 in the exploration, I changed the extension to be testuff. (Do this in the information window, otherwise the Finder will sometimes just hide the extension). My test application will still open the file correctly, if the extension is changed in the path.

If I now set "Open with:" to TextEdit or Smultron, it works properly. So the question is: what do these applications need to implement in order to respond properly to the double-click? What message does Launch Services send them?



The output from step 1 as displayed by NSLog (logging info removed):

fn = /Users/te/Desktop/x.txt
s1 = my data
URL = file://localhost/Users/te/Desktop/x.txt
s2 = my data


And the code listing:

// gcc -o test test.m -framework Foundation
// ./test
#import <Foundation/Foundation.h>

int main (int argc, const char * argv[]) {
NSAutoreleasePool *p;
p = [NSAutoreleasePool new];
NSString *s;
NSString *fn = NSHomeDirectory();
fn = [fn stringByAppendingString:
@"/Desktop/x.txt"];
NSError *e;
s = [NSString stringWithContentsOfFile:fn
encoding:NSASCIIStringEncoding
error:&e];
NSLog(@"fn = %@", fn);
NSLog(@"s1 = %@", s);

NSURL *fu;
fu = [NSURL fileURLWithPath:fn];
s = [NSString stringWithContentsOfURL:fu
encoding:NSASCIIStringEncoding
//encoding:NSUTF8StringEncoding
error:&e];
NSLog(@"URL = %@", fu);
NSLog(@"s2 = %@", s);
[p drain];
return 0;
}