Re: Temporarily disabling autosave
Re: Temporarily disabling autosave
- Subject: Re: Temporarily disabling autosave
- From: Alex Zavatone <email@hidden>
- Date: Fri, 19 Apr 2013 16:58:00 -0400
I think a good way of summing up your statement is "many developer type people would assume that a save of a document's data is a write of a delta of the data to a disk, which would take an amount of time that is so small that it would be transparent to the user".
It's apparent that with your doc, the app/doc could easily be in a state where letting auto save operate as it wishes could easily create cases where the user is blocked from using the app, or a resource intensive action is set up.
I'd hate to run in to this when on a laptop under battery.
I think that a related part of this is explained in Apple's docs on "Sudden and Unexpected Termination", in that there are times when an app just can't control alt delete/abort its running process.
One of these times where this is forbidden is when there are disk operations in queue.
Thinking from the 1000 foot view, if autosave is a "this thing is either on or off when the app starts and there's nothing you can do to change that once your app starts up", can you subclass part of autosave so as to check a BOOL that you have set in a supervisory role that is your permission slip to allow autosave to proceed or not?
On Apr 19, 2013, at 4:42 PM, Jerry Krinock wrote:
>
> On 2013 Apr 19, at 12:37, Mike Abdullah <email@hidden> wrote:
>
>> Why, what's wrong with cancelling a [auto]save?
>
> That's a damned good question, Mike. You're probably thinking that, hey, we lived without any autosaves from 1984 to 2011. What's the big deal? It turns out that you need to be really careful when playing around with an autosave that Cocoa has designated "not implicitly cancellable". Search the internet for:
>
> deadlock in -[NSDocument performActivityWithSynchronousWaiting:usingBlock:]
>
> to see some of the fun that people have had.
>
> I have an app with a requirement similar to Steve's. The app can do long-winded sequences of operations that take tens of seconds, and change the document. So if I honored an autosave request during one these sequences, I'd have to interrupt the operations (which is tricky), save, and then save again at the end after the changes were done.
>
> The solution: Upon receiving a non-cancellable autosave message while other operations are in progress, I stash the completion handler that Cocoa sends in the message, create an operation to "really autosave" later, and add it to my operation queue.
>
> I had to do other stuff to deal with corner cases such as Revert, being in the Versions Browser, etc. Below, I've snipped out a few of the relevant methods from my NSDocument (actually it's NSPersistentDocument, which adds even more to the mess) implementation.
>
> Jerry
>
> - (void)autosaveWithImplicitCancellability:(BOOL)autosavingIsImplicitlyCancellable
> completionHandler:(void (^)(NSError *errorOrNil))completionHandler {
> if (autosavingIsImplicitlyCancellable) {
> // We can cancel this autosave if we want to.
> if (
> // If operations are currently in progress, cancel it. This is
> // because we will save when our operations are complete.
> ([[[self operationQueue] operations] count] != 0)
> ||
> // Prevent unnecessary saves, in case the document is in a watched folder
> // that triggers a syncing mechanism.
> (![self isDocumentEdited])
> ) {
> // Cancel it.
> completionHandler([NSError errorWithDomain:NSCocoaErrorDomain
> code:NSUserCancelledError
> userInfo:nil]) ;
> return ;
> }
> }
>
> NSMutableDictionary* info = [NSMutableDictionary dictionary] ;
> [info setValue:Block_copy(completionHandler) forKey:constKeyCompletionHandler] ;
> [info setObject:self forKey:constKeyDocument] ;
> // The following adds a task to my home-made main operation
> // queue which I wrote back in the Leopard days …
> NSArray* selectorNames = [NSArray arrayWithObject:@"reallyAutosave"] ;
> [[self operationQueue] queueGroup:@"Non-cancellable Autosave"
> addon:NO
> selectorNames:selectorNames
> info:info
> block:NO
> owner:self
> doneThread:nil
> doneTarget:nil
> doneSelector:NULL
> keepWithNext:NO] ;
> [self setSavingState:1] ;
> }
>
>
> // This is the method that runs (in the main thread) to fulfill "reqllyAutosave"
>
> - (void)reallyAutosave_unsafe {
> NSDictionary* info = [self info] ;
> Bkmslf* bkmslf = [info objectForKey:constKeyDocument] ;
>
> void (^completionHandler)(NSError*) = [info objectForKey:constKeyCompletionHandler] ;
>
> [bkmslf reallyAutosaveWithCompletionHandler:completionHandler] ;
> // Note: completionHandler will be released by the receiver of the above message.
> }
>
> /*!
> @brief Override of new asynchronous saving method invoked by Cocoa
> when running in Mac OS X 10.7 or later.
> */
> - (void)saveToURL:(NSURL *)url
> ofType:(NSString *)typeName
> forSaveOperation:(NSSaveOperationType)saveOperation
> completionHandler:(void (^)(NSError *errorOrNil))completionHandler {
>
> [self prepareForSaveOperation:saveOperation] ;
>
> // Despite my best efforts to play nice with autosave, it still occasionally
> // deadlocked on me, until I added this:
> if ([self savingState] > 1) {
> NSLog(@"Warning 089-0831 Cancelling save, now in state %ld, from %@ to avoid deadlock", (long)[self savingState], SSYDebugCaller()) ;
> completionHandler([NSError errorWithDomain:NSCocoaErrorDomain
> code:NSUserCancelledError
> userInfo:nil]) ;
> return ;
> }
> [self setSavingState:2] ;
>
> [super saveToURL:url
> ofType:typeName
> forSaveOperation:saveOperation
> completionHandler:completionHandler] ;
> }
>
> - (void)doHousekeepingAfterSaveNotification:(NSNotification*)note {
> [self setSavingState:0] ;
>
> ...
> }
>
>
> _______________________________________________
>
> Cocoa-dev mailing list (email@hidden)
>
> 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:
>
> This email sent to email@hidden
_______________________________________________
Cocoa-dev mailing list (email@hidden)
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:
This email sent to email@hidden