Re: Saving only required files in a file wrapper?

2008-05-08 Thread Keith Blount
Many thanks again for your replies; much appreciated.

On the surface, it look as though Graham's suggested 
-writeToURL:ofType:forSaveOperation:originalContentsURL:error: would be the 
ideal solution, allowing me to write just individual files for an 
NSSaveOperation or copy the whole project for an NSSaveAsOperation.

The trouble is that the documentation is really unclear on this. It seems to 
say that you should use this method for exactly what I want but then it says 
that you can't rely on the URLs passed in!

Firstly, the docs say the following about this method:

You can override this method instead of one of the three simple writing 
methods... if your document writing machinery needs access to the on-disk 
representation of the document revision that is about to be overwritten.

Which is exactly what I want - I want access to the on-disk package where I 
know all of the contents are safe so that I can only save a handful of changed 
files within the package, without having to overwrite the entire package (which 
could take a long time for large packages).

However, it then goes on to say:

The value of absoluteURL is often not the same as [self fileURL]. Other times 
it is not the same as the URL for the final save destination. Likewise, 
absoluteOriginalContentsURL is often not the same value as [self fileURL].

Huh? It adds that If absoluteOriginalContentsURL is nil, either the document 
has never been saved or the user deleted the document file since it was 
opened. That bit makes sense. It is the above sentence that is worrying. I can 
see why absoluteURL wouldn't be the same as [self fileURL] if the save 
operation was NSSaveAsOperation (though the docs don't go into this). But 
outside of the document never having been saved or it having been deleted so 
that absoluteOriginalContentsURL is nil, why wouldn't 
absoluteOriginalContentsURL be the same as [self fileURL]?

On the other hand, if absoluteOriginalContentsURL represents a copy the OS has 
made of the package, then everything should be there and I should still be able 
to write to it and have the OS write everything back safely. Right? I hope. 
That is, I would expect this method - given that it says that you can use this 
method if your document writing machinery needs access to the on-disk 
representation of the document revision that is about to be overwritten - to 
at least provide a copy of the entire package at absoluteOriginalContentsURL 
even if that is not the original -fileURL. (To be really safe I could always 
check inside absoluteOriginalContentsURL to ensure that a file I know should be 
in every package is there...)

My experience certainly suggests that -fileURL will generally be the same as 
the passed-in URL. In my -readFromURL:... method, I have just realised that I'm 
calling -fileURL instead of absoluteURL, which I absolutely shouldn't be doing. 
But in two years not one of the thousands of users of my app has complained 
that their project wouldn't open. In the case of my app, though, the package is 
guaranteed to be on disk before -readFromURL: is ever called (you can't create 
a blank project without it already having a package on disk), so it seems that 
-absoluteURL in -readFromURL: only differs from [self fileURL] if the document 
is  a blank, unsaved one. (Obviously I can't rely on this behaviour and will be 
changing it to use -absoluteURL forthwith.)

Sorry for the long, rambling reply. I'm just trying to get my head around the 
best way of doing this, and the (usually excellent) docs seem a little obtuse 
in this area.

Many thanks again,
Keith
- Original Message 
From: Ken Thomases [EMAIL PROTECTED]
To: Graham Cox [EMAIL PROTECTED]
Cc: Keith Blount [EMAIL PROTECTED]; Cocoa-Dev List cocoa-dev@lists.apple.com
Sent: Thursday, May 8, 2008 3:36:05 AM
Subject: Re: Saving only required files in a file wrapper?

On May 7, 2008, at 9:06 PM, Graham Cox wrote:

 On 8 May 2008, at 10:26 am, Keith Blount wrote:

 The trouble with all of these methods is that they tell you not to  
 rely on fileURL

 My interpretation of that advice is that at the time the read... and  
 write... methods are called, the document hasn't set up -fileURL, so  
 in that sense you can't rely on it (i.e. don't call -fileURL from  
 within these methods). But the URL passed to the methods themselves  
 as a parameter is definitely reliable. So provided you use the  
 parameter you'll be fine.

I think it means more than that.  NSDocument tries to be smart about  
atomic writes and backups.  The URL passed into the write... methods  
is not expected to be the same as the document's current location on  
disk.  You are to write the document, in whole, to the temporary  
location provided to you (about which no assumptions should be made),  
and then NSDocument will take care of swapping the newly-written  
document with the old document and deleting the old document.

Obviously, this runs directly counter to Keith's desires

Re: Saving only required files in a file wrapper?

2008-05-08 Thread Keith Blount
Apologies for so soon a follow up, but I've just been experimenting with 
-writeToURL:ofType:forSaveOperation:originalContentsURL:error: and the results 
are disastrous. It turns out that *every single time* it is invoked, 
absoluteURL is a temporary location and *not* the original URL. So to use this 
method successfully I would need to copy the whole file package across to that 
location every time, which is exactly what I _don't_ want to do. This seems a 
little insane to me. There must be a mechanism in place that just lets you save 
into a package folder without having to write the whole thing out every time...

Thanks again and all the best,
Keith

- Original Message 
From: Ken Thomases [EMAIL PROTECTED]
To: Graham Cox [EMAIL PROTECTED]
Cc: Keith Blount [EMAIL PROTECTED]; Cocoa-Dev List cocoa-dev@lists.apple.com
Sent: Thursday, May 8, 2008 3:36:05 AM
Subject: Re: Saving only required files in a file wrapper?

On May 7, 2008, at 9:06 PM, Graham Cox wrote:

 On 8 May 2008, at 10:26 am, Keith Blount wrote:

 The trouble with all of these methods is that they tell you not to  
 rely on fileURL

 My interpretation of that advice is that at the time the read... and  
 write... methods are called, the document hasn't set up -fileURL, so  
 in that sense you can't rely on it (i.e. don't call -fileURL from  
 within these methods). But the URL passed to the methods themselves  
 as a parameter is definitely reliable. So provided you use the  
 parameter you'll be fine.

I think it means more than that.  NSDocument tries to be smart about  
atomic writes and backups.  The URL passed into the write... methods  
is not expected to be the same as the document's current location on  
disk.  You are to write the document, in whole, to the temporary  
location provided to you (about which no assumptions should be made),  
and then NSDocument will take care of swapping the newly-written  
document with the old document and deleting the old document.

Obviously, this runs directly counter to Keith's desires.  
Unfortunately, I don't know how to override these smarts in  
NSDocument, other than perhaps what I described earlier with  
NSFileWrapper.

-Ken



  

Be a better friend, newshound, and 
know-it-all with Yahoo! Mobile.  Try it now.  
http://mobile.yahoo.com/;_ylt=Ahu06i62sR8HDtDypao8Wcj9tAcJ
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to [EMAIL PROTECTED]


Re: Saving only required files in a file wrapper?

2008-05-08 Thread Michael Nickerson


On May 8, 2008, at 7:30 AM, Keith Blount wrote:

Apologies for so soon a follow up, but I've just been experimenting  
with -writeToURL:ofType:forSaveOperation:originalContentsURL:error:  
and the results are disastrous. It turns out that *every single  
time* it is invoked, absoluteURL is a temporary location and *not*  
the original URL. So to use this method successfully I would need to  
copy the whole file package across to that location every time,  
which is exactly what I _don't_ want to do. This seems a little  
insane to me. There must be a mechanism in place that just lets you  
save into a package folder without having to write the whole thing  
out every time...


Thanks again and all the best,
Keith



I went through some of this recently - I'm using a helper tool to  
actually save the files, and I had to figure some of this out to get  
that working right.


absoluteURL is going to always be a temp location because that's how  
the document system works - it writes to the temp location, then  
overwrites the original location if that's successful.  Keeps file  
corruption to a minimum.


absoluteOriginalContentsURL should probably be the original URL.  The  
only time it's not likely to be the original path (what's returned by  
[self fileURL]) is if the user has moved / renamed the original file  
in between when it was opened and when it's being saved.  (I'm fairly  
certain this is why you're told not to use -fileURL when writing -  
because that's not updated if the user moves / renames the file while  
it's being edited.)


If you don't want to rely on that, there's nothing stopping you from  
creating a new ivar to save the URL passed in when you read the file.   
Though that can break if the user moves / renames the file while it's  
being edited.  I know, not likely, but you can't be 100% certain on  
that.  If you'd like to do this, but want to be certain, you could get  
the original path when you read and convert it to a file alias, then  
resolve the alias when you're writing - then you're guaranteed to have  
the correct path (this is what I actually decided to do).  The only  
way that would break is if the user moves the file to a different hard  
drive, and I believe the normal NSDocument methods wouldn't work  
correctly in that case anyway (I believe the user gets shown a dialog  
saying the original file couldn't be found).


Once you have the original path (whichever way you choose to get it),  
you can do what you were before to save the files in the wrapper.  Or,  
if you want to, you can save it to the temp location, and then  
overwrite the individual files yourself using NSFileManager.  Though  
if you do that, *make sure to delete the temp file* before returning  
(if you use the same path as absoluteURL for the temp file, anyway).   
If you don't, the document system will copy it over anyway and you'll  
wind up with your original problem. I had an interesting time figuring  
that last part out.  In my case, the original files aren't actually  
writable by anyone but root, and it would fail when it tried to copy  
the temp files over the original files (even though my helper tool had  
actually already done that).  Made for an interesting case where the  
file was actually saved but the app didn't think so.


Hope that helps out some.


--
Darkshadow
(aka Michael Nickerson)
http://www.nightproductions.net


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to [EMAIL PROTECTED]


Re: Saving only required files in a file wrapper?

2008-05-08 Thread Keith Blount
Hi,

Many thanks for your reply, much appreciated - it all helps. I've spent the 
last couple of hours digging deeper into this, and I think what I'm going to 
try to do next is override at a slightly lower level, by overriding 
-writeSafelyToURL:ofType:forSaveOperation:error:. I found the part of the 
documentation that shows a diagram of the sequence of save events, and it turns 
out that this is the method that sets up the temporary folders and URLs that 
get passed into -writeToURL:... If I override and do my writing inside the 
package there, I think it should work. The docs say that you should always call 
super inside that method, but I found an Apple sample project, 
QTKitCreateMovie, that doesn't, and which shows this method being overridden to 
do something similar to what I want to do. Certainly that is the method that 
creates the behaviour that I want to change, so I am hopeful...

Thanks again and all the best,
Keith

- Original Message 
From: Michael Nickerson [EMAIL PROTECTED]
To: Keith Blount [EMAIL PROTECTED]
Cc: Cocoa-Dev List cocoa-dev@lists.apple.com
Sent: Thursday, May 8, 2008 5:45:10 PM
Subject: Re: Saving only required files in a file wrapper?


On May 8, 2008, at 7:30 AM, Keith Blount wrote:

 Apologies for so soon a follow up, but I've just been experimenting  
 with -writeToURL:ofType:forSaveOperation:originalContentsURL:error:  
 and the results are disastrous. It turns out that *every single  
 time* it is invoked, absoluteURL is a temporary location and *not*  
 the original URL. So to use this method successfully I would need to  
 copy the whole file package across to that location every time,  
 which is exactly what I _don't_ want to do. This seems a little  
 insane to me. There must be a mechanism in place that just lets you  
 save into a package folder without having to write the whole thing  
 out every time...

 Thanks again and all the best,
 Keith


I went through some of this recently - I'm using a helper tool to  
actually save the files, and I had to figure some of this out to get  
that working right.

absoluteURL is going to always be a temp location because that's how  
the document system works - it writes to the temp location, then  
overwrites the original location if that's successful.  Keeps file  
corruption to a minimum.

absoluteOriginalContentsURL should probably be the original URL.  The  
only time it's not likely to be the original path (what's returned by  
[self fileURL]) is if the user has moved / renamed the original file  
in between when it was opened and when it's being saved.  (I'm fairly  
certain this is why you're told not to use -fileURL when writing -  
because that's not updated if the user moves / renames the file while  
it's being edited.)

If you don't want to rely on that, there's nothing stopping you from  
creating a new ivar to save the URL passed in when you read the file.  
Though that can break if the user moves / renames the file while it's  
being edited.  I know, not likely, but you can't be 100% certain on  
that.  If you'd like to do this, but want to be certain, you could get  
the original path when you read and convert it to a file alias, then  
resolve the alias when you're writing - then you're guaranteed to have  
the correct path (this is what I actually decided to do).  The only  
way that would break is if the user moves the file to a different hard  
drive, and I believe the normal NSDocument methods wouldn't work  
correctly in that case anyway (I believe the user gets shown a dialog  
saying the original file couldn't be found).

Once you have the original path (whichever way you choose to get it),  
you can do what you were before to save the files in the wrapper.  Or,  
if you want to, you can save it to the temp location, and then  
overwrite the individual files yourself using NSFileManager.  Though  
if you do that, *make sure to delete the temp file* before returning  
(if you use the same path as absoluteURL for the temp file, anyway).  
If you don't, the document system will copy it over anyway and you'll  
wind up with your original problem. I had an interesting time figuring  
that last part out.  In my case, the original files aren't actually  
writable by anyone but root, and it would fail when it tried to copy  
the temp files over the original files (even though my helper tool had  
actually already done that).  Made for an interesting case where the  
file was actually saved but the app didn't think so.

Hope that helps out some.


--
Darkshadow
(aka Michael Nickerson)
http://www.nightproductions.net


  

Be a better friend, newshound, and 
know-it-all with Yahoo! Mobile.  Try it now.  
http://mobile.yahoo.com/;_ylt=Ahu06i62sR8HDtDypao8Wcj9tAcJ
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do

Re: Saving only required files in a file wrapper?

2008-05-07 Thread Keith Blount
Hi Ken,

Many thanks for your response... Hmm, I think you're right. I overrided 
-saveDocument: because it looked as though -writeToURL: and all of the other 
-write... methods expected you to write all the data at any one time. It's 
possible for my file packages to run to hundreds of megabytes, so I only ever 
want to write the changed files at any save point (usually only ever one or two 
RTFD files within the package actually require saving at any one time). There's 
not much in the docs about doing this - everything I can find seems to assume 
that you will save everything, even when it comes to packages (as file 
wrappers), at once, which is why I took a screwy way. I still wonder what the 
best way of doing it is. 
-writeToURL:ofType:forSaveOperation:originalContentsURL:error: perhaps?

Also, is it possible that -writeToURL: is getting called behind the back of 
-saveDocument:? I considered this but assumed (always a bad mistake) that it 
would be safe as I thought that all of the -write... methods did nothing unless 
you overrode them.

Many thanks again.

All the best,
Keith

P.S. I've updated the thread title to better reflect the problem.

- Original Message 
From: Ken Thomases [EMAIL PROTECTED]
To: Keith Blount [EMAIL PROTECTED]
Cc: cocoa-dev@lists.apple.com
Sent: Wednesday, May 7, 2008 4:03:23 PM
Subject: Re: Deep sleep and file wrappers?

I don't have experience with NSDocument-based applications, so take  
the following with a grain of salt...

On May 6, 2008, at 1:27 PM, Keith Blount wrote:

 I have an application that saves its information as a file package.  
 My NSDocument subclass overrides -saveDocument: to save individual  
 files within the project folder (because there can be hundreds of  
 files and I wouldn't want to save the whole file wrapper every time  
 a single file is changed).

From the docs, this doesn't seem like the right way to customize  
saving.  Overriding -saveDocument: may catch some cases of save  
attempts, but I suspect there are other times when other methods are  
invoked directly.  This document describes what you need to override  
to customize how the document is saved:

http://developer.apple.com/documentation/Cocoa/Conceptual/Documents/Tasks/SubclassNSDocument.html


 I never got to the bottom of the issue, and now another user has  
 reported the same thing. To recap: whilst my app was open, the  
 user's computer went into deep sleep (this was the case with the  
 first two users; the third user cannot remember the exact  
 circumstances but says his computer has had deep sleep problems  
 recently). When it came out of deep sleep, everything in the  
 project's file wrapper - that is, everything in the folder-with- 
 extension on disk - had been wiped. All that was in there were the  
 few files that were auto-saved _after_ deep sleep.

I can think of two possibilities:

1) some other method was invoked to save the document, but since you  
didn't override it, it produced an empty document.  The framework then  
replaced the existing document on disk with the new empty document.

2) The framework sometimes juggles files to perform an atomic  
document save operation.  The writing methods of NSDocument are told  
to write to a different, temporary location, then the original and the  
newly saved document are swapped, then the backup is removed (unless - 
keepBackupFile is overridden to return YES).  If this happens in your  
case, the new document will not be complete because of the way you're  
only saving part of the document.


Good luck finding and fixing the problem,
Ken



  

Be a better friend, newshound, and 
know-it-all with Yahoo! Mobile.  Try it now.  
http://mobile.yahoo.com/;_ylt=Ahu06i62sR8HDtDypao8Wcj9tAcJ
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to [EMAIL PROTECTED]


Re: Saving only required files in a file wrapper?

2008-05-07 Thread Ken Thomases

Hi,

On May 7, 2008, at 3:08 PM, Keith Blount wrote:


Many thanks for your response...


Sure thing.  I'm happy to flail in the dark and guess wildly with the  
best of them.  ;)


Hmm, I think you're right. I overrided -saveDocument: because it  
looked as though -writeToURL: and all of the other -write... methods  
expected you to write all the data at any one time. It's possible  
for my file packages to run to hundreds of megabytes, so I only ever  
want to write the changed files at any save point (usually only ever  
one or two RTFD files within the package actually require saving at  
any one time). There's not much in the docs about doing this -  
everything I can find seems to assume that you will save everything,  
even when it comes to packages (as file wrappers), at once, which is  
why I took a screwy way.


Yeah, it's hard to see how one can accomplish what you're trying to do.

I wonder...  what happens if you compose a directory NSFileWrapper  
from an existing directory (which will recursively fill it with file  
wrappers referencing the directory's contents), then remove the  
wrappers for the individual items you want to replace, then add new  
file wrappers for those items, then save that whole file wrapper to  
the desired destination location?  Are there any smarts in there to  
avoid doing a full copy of all of the items which weren't changed,  
perhaps using hard links or the like?


I still wonder what the best way of doing it is. - 
writeToURL:ofType:forSaveOperation:originalContentsURL:error: perhaps?


Well, that seems to give you the greatest flexibility, and gives you  
both the new and old URLs, but -- by the very fact that you're given  
two URLs -- the explicit fact is that you are creating a new document  
on disk rather than doing a minimal modification of the old one.  So,  
you'd have to perform the copy of all of the parts that are the same  
between the two, which is what you're trying to avoid.



Also, is it possible that -writeToURL: is getting called behind the  
back of -saveDocument:? I considered this but assumed (always a bad  
mistake) that it would be safe as I thought that all of the - 
write... methods did nothing unless you overrode them.


I don't know.  That's certainly one of the possibilities I  
considered.  I think you have to assume it's possible.  For instance,  
I would not expect the auto-save features of NSDocument to go through - 
saveDocument:.  -saveDocument: is an action method, intended to be  
triggered by the Save menu item (and similar GUI controls).  So, I  
would expect that it would have all sorts of high-level functionality  
like running a save panel if the document hasn't been saved before.   
Because of that, the framework wouldn't use it when it needs to do  
something low-level.


Cheers,
Ken
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to [EMAIL PROTECTED]


Re: Saving only required files in a file wrapper?

2008-05-07 Thread Graham Cox


On 8 May 2008, at 10:26 am, Keith Blount wrote:

The trouble with all of these methods is that they tell you not to  
rely on fileURL



My interpretation of that advice is that at the time the read... and  
write... methods are called, the document hasn't set up -fileURL, so  
in that sense you can't rely on it (i.e. don't call -fileURL from  
within these methods). But the URL passed to the methods themselves as  
a parameter is definitely reliable. So provided you use the parameter  
you'll be fine. If you call other parts of your code that need the URL  
from inside these methods, you also need to pass them the URL  
directly, don't let them fetch it using -fileURL.


A potential issue is if your users use Save As.. to save to a  
completely new file. In that case there is:


writeToURL:ofType:forSaveOperation:originalContentsURL:error:

so you have the original file URL as well so you can copy across other  
parts of the package to the new file. Again, there's no need to call - 
fileURL at that time, which may or may not refer to the original file.


hth,

G.
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to [EMAIL PROTECTED]


Re: Saving only required files in a file wrapper?

2008-05-07 Thread Ken Thomases

On May 7, 2008, at 9:06 PM, Graham Cox wrote:


On 8 May 2008, at 10:26 am, Keith Blount wrote:

The trouble with all of these methods is that they tell you not to  
rely on fileURL


My interpretation of that advice is that at the time the read... and  
write... methods are called, the document hasn't set up -fileURL, so  
in that sense you can't rely on it (i.e. don't call -fileURL from  
within these methods). But the URL passed to the methods themselves  
as a parameter is definitely reliable. So provided you use the  
parameter you'll be fine.


I think it means more than that.  NSDocument tries to be smart about  
atomic writes and backups.  The URL passed into the write... methods  
is not expected to be the same as the document's current location on  
disk.  You are to write the document, in whole, to the temporary  
location provided to you (about which no assumptions should be made),  
and then NSDocument will take care of swapping the newly-written  
document with the old document and deleting the old document.


Obviously, this runs directly counter to Keith's desires.   
Unfortunately, I don't know how to override these smarts in  
NSDocument, other than perhaps what I described earlier with  
NSFileWrapper.


-Ken
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to [EMAIL PROTECTED]