Bypassing Open and Save of the NSDocument class


Is it possible to implement the built-in mechanism of NSDocument for opening and writing to a file? My app is not Document-oriented, all is done in a single window, but I want to use the encoding/decoding process described in the book “AppleScriptObjC Explored” to read and write to and from separate files.

Can it be done, and how?

Thank you!

Well your looking for serialisation. NSArchiver and NSUnArchiver or NSKeyedArchiver and NSKeyedUnArchiver can handle your own storing and loading your objects in different files. read “Archives and Serializations Programming Guide” for more information about serialisation and archiving to store objects into a file and open them later (open and save).

Ok, so I put these lines:

set someData to current application's NSMutableData's |data|()
set theEncoder to current application's NSKeyedArchiver's alloc()'s initForWritingWithMutableData_(someData)
tell theEncoder
   encodeObject_forKey_(cardHeader, "cardHeader") -- declared as property cardHeader : class "NSString"
   encodeObject_forKey_(cardImage, "cardImage") -- declared as property cardImage : class "NSImage"
end tell

I got this error: +[NSImage encodeWithCoder:]: unrecognized selector sent to class 0x7fff705c6440

Are NSImages no encodable? the book used an image for example…

And when I have finish with this encoding, what shall I do with this “someData” to put it into a file? I suppose it’s something more intricate that addResource( handle(myPicture),“PICT”,128,“” ) :confused:

Nevertheless, thank you for the link!
“There is always another bug.” (Anonymous)

That error says you’re trying to call a class method (the +) – you’re trying to archive the NSImage class, not an instance of it.

Actually it’s less intricate:

tell someData to writeToFile_atomically_("/path/to/file", true)

OK, Shane, so I must declare:

property myText : missing value
property myImage : missing value
property mySound : missing value

to make instances, and then initialize them, by binding with elements in IB or by coding (say, in applicationWillFinishLaunching_) : set myImage to current application’s NSImage’s alloc()'s init(), for example?

And then my encoder/decoder will do what I’m expecting for hours?

Poor fool, I wanted to understand the whole thing in a couple of days…:frowning:

This would create an instance of an NSImage, but it would be empty (no image). You should use one of the many initWith… methods of NSImage (current application’s NSImage’s alloc()'s initWithContentsOfURL_(aURL) for example) or use current application’s NSImage’s imageNamed_(“myImageName”). It depends on how you are storing your images.


One of my big problems is to access the file… I’m confused among these path, URL, HFSpath, etc… my program find the correct file but is unable to write into it, or it writes the correct content but in strange places…

The “path” returned with a “choose file” has nothing to do with the parameter expected by a writeToFile method. Why have things become so complicated? Because of the irruption of Unix in the MacOS? It could have been MS-DOS as well… I don’t dare to imagine the conversions to get the right thing at the write place!

Or am I missing something important?

Maybe I could let Cocoa work for me :confused:

I’m investigating this “rtfd” format, which could save onto a file a great part of what I need (the rest will be dropped, but the idea of putting images and sounds in the textView is seducing enough to make me rebuild the concept of my application)…

Stand by, friends, I’ll nee your help for sure :wink:

A programming language is almost the same as a spoken language, you can’t learn it in a few days.
It’s quite painful to learn Objective-C / ASOC but it’s worth it and then it’s cool as to be in a foreign country and understand what the people are saying. :wink:

It’s not complicated. When AppleScript was introduced (System 7 ?) , the HFS file system was based on colon separated paths so AppleScript uses them, too. However, UNIX (and Cocoa) works with POSIX paths (slash separated).

choose file returns an alias specifier, which can be coerced to a HFS path

(choose file) as text

or to a POSIX path

POSIX path of (choose file)

If you are accessing your images from a file, it is easy to use an NSOpenPanel to get the URL of the file, and then use initWithContentsOfURL method to get the data – you don’t need to do any path manipulations. As an example, the following code uses an open panel (configured as a “choose” panel to pick files but not directories) to load an image into an imageView:

script ChooseDialogAppDelegate
	property parent : class "NSObject"
	property iv : missing value -- Connected to an NSImageView
	on applicationWillFinishLaunching_(aNotification)
		set op to current application's NSOpenPanel's openPanel()
		op's setCanChooseFiles_(1)
		op's setCanChooseDirectories_(0)
		op's setTitle_("choose an Image File")
		op's setPrompt_("Choose")
		op's runModal()
		set theURL to op's URLs()'s objectAtIndex_(0)
		set theImage to current application's NSImage's alloc()'s initWithContentsOfURL_(theURL)
		iv's setImage_(theImage)
	end applicationWillFinishLaunching_
end script

The other easy way to do it, if you don’t have too many files, is to drag the files into your resources folder of your project, then you can access them with NSImage’s imageNamed_(“imagename”) which will find them without any path information.


Well it’s not that complicated at all.

Applescript uses since Mac OS 7 macintosh paths and it would give many scripts problems when aliases where posix path in OS X. Also to let the carbon applications from OS 9 run smoothly in OS X the same rule was applied for Carbon. The reason why carbon and applescript uses both posix and macintosh paths is clear. Cocoa work(ed) a lot with carbon in it’s beginning, so it was naturally that in some case you can use macintosh paths in cocoa as well. So thinking that it could have been MS-DOS as well is wrong. It’s posix path by default and the macintosh path is an addition for the programmer.

in short: The whole posix and macintosh paths misunderstandings comes from the Mac OS 9 to Mac OS X switch.

Ok, I think I get it. I did never program under macOS X because my compiler generated MC68000 code (yes, I’m that old:().

So if I use set myPOSIXPath to POSIX path of myHFSPath I get the “/xxx/yyy/” from the “xxx:yyy:”
and set myHFSPath to (POSIX file myPOSIXPath) as string give me the reverse conversion?

This explains my previous post about my files strange locations :confused: Thank you so much!

And what is the URL path? just another name for POSIX or is it really an Internet address?


No. You have to say:

set myHFSPath to (myPOSIXPath as POSIX file) as text

There’s a quirk in AppleScriptObjC that means you have to use POSIX file as a coercion, not as a specifier.

It looks like an internet address, but has file:// at the front instead of http:// It seems like Apple is moving toward using URLs for file references and have depreciated some of the initWithContentsOfFile type methods in favor of initWithContentsOfURL types.

An example of a file URL would be: file://localhost/Users/johndoe/Documents/TilePlan.tiff


I worked with UNIX 25 years ago… but I remember that “/” was for “one directory up”. Can I safely use URL and POSIX indifferently or make URL a different path of POSIX?

Meanwhile, I made some progress with file locations, and discovered that writeToFile creates the file if it doesn’t exist, so my “tell Finder to make new file at” was superfluous (did you realize that documentation is always clearer after you made every possible mistake, or am I just obtuse?)

Even AppleScript is using them these days. Run “choose file name” and the class of the result is «class furl», which is a file URL wrapped up for AS.

        set err to gTextView's readRTFDFromFile_(gFolderPOSIXPath & theID as string&".atxt", true)

and the reverse

        set theData to gTextView's RTFDFromRange_({|location|:0, |length|:gTextView's |string|()'s |length|()})
        tell theData to writeRTFDToFile_atomically_(gFolderPOSIXPath & theID as string&".atxt", true)

gives error

2011-03-17 23:37:05.345 AutoText[11366:903] -[NSConcreteMutableData writeRTFDToFile:atomically:]: unrecognized selector sent to instance 0x2002a8a40

but I followed the method protocols… what’s wrong?

writeRTFDToFile is a method of class NSText, there is none in class NS(Mutable)Data
As the NSData object contains the RTFD data anyway, just use the simple writeToFile method

RTFDFromRange_ is returning an NSData object, and you can’t call the NSText method writeRTFDToFile_atomically_ on NSData. Use writeRTFDToFile_atomically_ to write the whole contents, or get the data and use one of NSData’s methods to write to to a file (like writeToFile:atomically:).

set err to gTextView’s readRTFDFromFile_(gFolderPOSIXPath & theID as string&“.atxt”, true)
gTextView’s writeRTFDToFile_atomically_(gFolderPOSIXPath & theID as string&“.atxt”, true)
give incompatible results.

writeRTFDToFile creates a folder in with I have a “TXT.rtf” file (similar to the .rtfd, but without the “wrapper” to make it appear as a single “file”.

… and of course readRTFDFromFile cannot find the file.

If I change to a single writeToFile, readRTFDFromFile returns some format data, making the file unreadable.

In fact, I want my app to make exactly what TextEdit does – it must be possible?