PDA

View Full Version : Adding a custom UTI to a document app




mdeh
Nov 8, 2009, 12:53 PM
Well...my questions have had plenty of views, but no answers ....yet :D

I am still playing around with pasteboards...slowly making progress. I **think** this is easy, but have not been able to find a good example.

Lets say I have declared a custom UTI in a doc-based application. ...lets call it "com.myCompany.BookMarkUTI".

**How** exactly do I add it to the plist ( I am assuming that *that* is indeed where it is added). ( And if the answer is to use the plist editor, which category is it added to)?


Thanks in advance.



chown33
Nov 8, 2009, 03:09 PM
http://developer.apple.com/mac/library/documentation/General/Reference/InfoPlistKeyReference/Articles/GeneralPurposeKeys.html

Google search terms: property list uti site:developer.apple.com

mdeh
Nov 8, 2009, 04:34 PM
http://developer.apple.com/mac/library/documentation/General/Reference/InfoPlistKeyReference/Articles/GeneralPurposeKeys.html

Google search terms: property list uti site:developer.apple.com

Yes...that helps...almost. I think the issue is not so much that I have not read about it, as more that the concept is not yet entirely clear! :)


How does this look to you? (This is in the "event class" which contains ivars like date, name, etc.


Added this to the info.plist...hopefully the image is legible.


202348


Now, in code, ( all related to pasteboard) this:

I *hope* that the cast is correct in the define statement...as the app crashes, but not sure if it is related to this , yet!


#define MYUTI (NSString*)"com.testMode.Event_UTI"

.......other stuff.........

- (NSArray *)writableTypesForPasteboard: (NSPasteboard *)pasteboard
{
NSArray *typeArray = [NSArray arrayWithObjects: (NSString *)kUTTypeURL, NSPasteboardTypeString, MYUTI, nil];
return typeArray;
}


- (id)pasteboardPropertyListForType: (NSString *)type
{

if ( [ type isEqual:MYUTI] )
NSLog(@"Eureka");
return [ NSKeyedArchiver archivedDataWithRootObject:self];
}


Now, I am **assuming** ( never smart) that the method

"- (id)pasteboardPropertyListForType: (NSString *)type"

is essentially saying, "How do you want me to handle this type?"

Thanks.

chown33
Nov 8, 2009, 05:41 PM
The best way to see what makes a valid UTI is to open the plist of an app that has valid UTIs.

You should also look at sample code.
For example, google the words: uti sample code site:developer.apple.com


#define MYUTI (NSString*)"com.testMode.Event_UTI"

I didn't look closely at your code, but that is very wrong. It should be:

#define MYUTI @"com.testMode.Event_UTI"

mdeh
Nov 8, 2009, 06:10 PM
The best way to see what makes a valid UTI is to open the plist of an app that has valid UTIs.

You should also look at sample code.
For example, google the words: uti sample code site:developer.apple.com


#define MYUTI (NSString*)"com.testMode.Event_UTI"

I didn't look closely at your code, but that is very wrong. It should be:

#define MYUTI @"com.testMode.Event_UTI"



I agree about looking at code....but I had a hard time finding any samples. Your search method helps. As to the string, I assumed, as UTIs are CFStrings, and as I had seen in the documentation, that there is "toll-free" bridging" between and NSString and a CFString, that I needed a caste to use it as an NSString. I had seen this done elsewhere. But, I guess , if one **starts** in an Obj-C environment, one can assume Xcode treats it as an NSString...if that even makes sense.

chown33
Nov 8, 2009, 07:35 PM
There is toll-free bridging between CFString and NSString*. That's not the problem.

The problem is that this:

"any.text.you.care to put here"

is a C string literal. It is not a CFString nor NSString*.

A C string literal is an array of char with a null terminator. It's not an object, and casting it to NSString* doesn't make it one.

mdeh
Nov 9, 2009, 09:39 PM
There is toll-free bridging between CFString and NSString*. That's not the problem.

The problem is that this:

"any.text.you.care to put here"

is a C string literal. It is not a CFString nor NSString*.

A C string literal is an array of char with a null terminator. It's not an object, and casting it to NSString* doesn't make it one.

Hi Chown,
Well...have done a lot of reading about CFString...I like to understand things..as you can see. So, this from the Apple Docs

CFString is “toll-free bridged” with its Cocoa Foundation counterpart, NSString. This means that the Core Foundation type is interchangeable in function or method calls with the bridged Foundation object. Therefore, in a method where you see an NSString * parameter, you can pass in a CFStringRef, and in a function where you see a CFStringRef parameter, you can pass in an NSString instance. This also applies to concrete subclasses of NSString. See Interchangeable Data Types for more information on toll-free bridging.

So, ran this little test code.


#import <Foundation/Foundation.h>


int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

CFStringRef str = CFSTR( "Hello World");
CFShow(str);
NSString *str_2 = (NSString *) str;

NSLog(@"\n%@", str_2);


[pool drain];
return 0;
}


output:

Hello World
2009-11-09 19:33:30.492 StringStuff[553:a0f]
Hello World



BTW...thanks for all your help.

Sander
Nov 10, 2009, 03:19 AM
CFStringRef str = CFSTR( "Hello World");



That's not the same thing as was in your original example though. The CFSTR wasn't there, and like chown33 said, you were trying to cast a C string literal to an NSString*. Unfortunately, a cast is a powerful construct which basically tells the compiler "Trust me, I know what I'm doing."

By the way, in my experience it's best to keep UTIs in all lower case. I found out yesterday that when saving a document in my own file type I received the UTI with the same capitalization as I put it in my .plist, but when loading it, it was all lowercase (so it wasn't recognized by my straight string compare).

Also of note is that in 10.4, the writeToURL and readFromURL methods on my NSDocument subclass got the "human readable" type name as the typeName parameter, whereas on 10.5 they get the UTI.

mdeh
Nov 10, 2009, 07:38 AM
That's not the same thing as was in your original example though. The CFSTR wasn't there, and like chown33 said, you were trying to cast a C string literal to an NSString*. Unfortunately, a cast is a powerful construct which basically tells the compiler "Trust me, I know what I'm doing."

Agreed! The problem is that you are on the **other** side of the learning curve :). I am still trying to figure these things out...and it's a very steep road to hoe. So, if my questions sometimes do not make good sense, it's because I have not quite articulated in my own mind exactly what it is that I do not understand. So, the help received here is invaluable in a) helping to focus on the exact issue ( which more than often is not what was asked in the first place) and b) providing, often , the thread upon which to hang the myriad of facts that one has processed in a somewhat disorderly fashion.


By the way, in my experience it's best to keep UTIs in all lower case. I found out yesterday that when saving a document in my own file type I received the UTI with the same capitalization as I put it in my .plist, but when loading it, it was all lowercase (so it wasn't recognized by my straight string compare).

Will keep that in mind.


Also of note is that in 10.4, the writeToURL and readFromURL methods on my NSDocument subclass got the "human readable" type name as the typeName parameter, whereas on 10.5 they get the UTI.

Sander...could you perhaps just give an example of the last issue.

Thanks in advance. Your input is much appreciated.

Sander
Nov 11, 2009, 03:34 PM
Sander...could you perhaps just give an example of the last issue.

I am developing an app and wanted to keep compatibilty with 10.4. I assume you know how loading and saving works in a document-based app. I chose to override writeToURL: ofType: error: and readFromURL: ofType: error:. An UTI also has a "human-readable" representation, which you can see in the "Save As..." file types popup menu of your app. For example, it might say "Portable Network Graphics image" instead of "public.png" there.

In 10.4, the "ofType" parameter would be "Portable Network Graphics image". That's a big nuisance, because I can't map this back onto the real UTI. I had to resort to an ugly hack (looking at the file extension - so Windows!).

I then compiled for 10.5, and to my surprise, the ofType parameter is now "public.png".