Re: Telling Auto Save, "No, I'm busy now"
Re: Telling Auto Save, "No, I'm busy now"
- Subject: Re: Telling Auto Save, "No, I'm busy now"
- From: Kevin Perry <email@hidden>
- Date: Mon, 8 Aug 2011 09:29:01 -0700
Ah, I did not foresee this.
I really can't generally recommend calling -saveToURL:::error: instead of saveToURL:::completionHandler: because the latter does some important things that the former doesn't. Unfortunately, I think the problem you're seeing with the hang is insurmountable without additional API. Here's what normally happens:
1) -autosaveWithImplicitCancellability:completionHandler: uses -performAsynchronousFileAccessUsingBlock:
2) Within that block, it calls -saveToURL:::completionHandler:
3) -saveToURL:::completionHandler: of necessity also uses -performAsynchronousFileAccessUsingBlock:. When invoked in the above block, NSDocument recognizes this as a continuation of the initial -performAsynchronousFileAccessUsingBlock: call and simply invokes the block right away.
However, in your case, you are delaying step (3) until outside the initial block, so NSDocument cannot automatically recognize this as a continuation of the same file access. In order to resolve this, you would need API on NSDocument to tell it that you're continuing the same file access from before when you reinvoke -saveToURL:::completionHandler:.
Actually, you may be able to work around this problem by overriding -autosaveWithImplicitCancellability:completionHandler: instead (also?) and doing the same approach of delaying NSDocument's code until once you've completed the background work.
-KP
On Aug 6, 2011, at 7:23 AM, Jerry Krinock wrote:
> ** One little surprise. After dequeueing the save operation, I kind of thought that I could invoke the new synchronous saving method saveToURL:::completionHandler:. However, this does not save and apparently does not run the completion handler properly because I still get the hanging/blocking in -[NSDocument performAsynchronousFileAccessUsingBlock:]. But if I invoke the old async -saveToURL:::error: method and invoke the completion handler block "manually", it works fine. Here…
>
> /*!
> @brief Real saving method, invoked when a save operation is
> dequeued to do the actual work.
> */
> - (void)reallySaveToURL:(NSURL *)url
> ofType:(NSString *)typeName
> forSaveOperation:(NSSaveOperationType)saveOperation
> completionHandler:(void (^)(NSError *errorOrNil))completionHandler {
> [self prepareForSaveOperation:saveOperation] ;
>
> #if 0
> #warning Using fancy new async saveToURL::::. Doesn't work.
> [super saveToURL:url
> ofType:typeName
> forSaveOperation:saveOperation
> completionHandler:completionHandler] ;
> // Still hangs even if the following is commented out.
> Block_release(completionHandler) ;
> #else
> #warning Invoking completionHandler manually. This works.
> NSError* error = nil ;
> BOOL ok = [super saveToURL:url
> ofType:typeName
> forSaveOperation:saveOperation
> error:&error] ;
> completionHandler(error) ;
> Block_release(completionHandler) ;
> if (error && ok) {
> NSLog(@"Internal Error 923-0284 %@", error) ;
> }
> #endif
> }
>
>
> /*!
> @brief Override of new asynchronous saving method invoked by Cocoa
> when running in Mac OS X 10.7 or later.
>
> @details
>
> * Case saveOperation maenQueue Cancellable? Action
> * ---- ------------- --------- ------------ --------------------
> * 1 not AIP X X Add to queue
> * 2 AIP not busy X Add to (empty) queue
> * 3 AIP busy Yes Cancel the Save
> * 4 AIP busy No Add to (busy) queue
>
> AIP = Auto Save In Place
> X = don't care
> */
> - (void)saveToURL:(NSURL *)url
> ofType:(NSString *)typeName
> forSaveOperation:(NSSaveOperationType)saveOperation
> completionHandler:(void (^)(NSError *errorOrNil))completionHandler {
> if (saveOperation == NSAutosaveInPlaceOperation) {
> // Case 2, 3 or 4
> if ([[[SSYOperationQueue maenQueue] operations] count] != 0) {
> // Case 3 or 4 (busy)
> if ([self autosavingIsImplicitlyCancellable]) {
> // Case 3. Cancel the Save
> completionHandler([NSError errorWithDomain:NSCocoaErrorDomain
> code:NSUserCancelledError
> userInfo:nil]) ;
> /*DB?Line*/ NSLog(@"133955: Cancelling Save") ;
> return ;
> }
> else {
> // Case 4. Add to (busy) queue
> }
> }
> else {
> // Case 2. Add to (empty) queue
> }
> }
> else {
> // Case 1. Add to queue
> }
>
> // Note that we arrive here either in Case 1, 2 or 4.
> // In Case 2, and maybe Case 1, instead of adding the save
> // operation to our queue, we could invoke -reallySaveToURL::::
> // synchronously. However we don't do that because the usual
> // notification sent when work is done, which we need for
> // housekeeping, would not be sent, and also it would be
> // extra code and an extra branch which means more testing
> // and bug possibilities.
>
> <snip>
> … Code here adds operation to my SSYOperationQueue, kind of a
> … cheesy main operation queue which I wrote back in the Leopard days
> … for this project. It also copies the completionHandler block…
> [info setValue:Block_copy(completionHandler) forKey:kCompletionHandler] ;
> … When operation is dequeued, it invokes reallySaveToURL::::.
> </snip>
> }
>
> _______________________________________________
>
> 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
References: | |
| >Re: Telling Auto Save, "No, I'm busy now" (From: Kevin Perry <email@hidden>) |
| >Re: Telling Auto Save, "No, I'm busy now" (From: Jerry Krinock <email@hidden>) |
| >Re: Telling Auto Save, "No, I'm busy now" (From: Ken Thomases <email@hidden>) |
| >Re: Telling Auto Save, "No, I'm busy now" (From: Kevin Perry <email@hidden>) |
| >Re: Telling Auto Save, "No, I'm busy now" (From: Jerry Krinock <email@hidden>) |