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 (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/kperry%40apple.com
> 
> This email sent to kpe...@apple.com

_______________________________________________

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 arch...@mail-archive.com

Reply via email to