title: Failed attempt using Related Items to create backup file in sandboxed app
body: <p>The App Sandbox design guide says:</p>
  
  <blockquote>
    <p>The related items feature of App Sandbox lets your app access files
    that have the same name as a user-chosen file, but a different
    extension. This feature consists of two parts: a list of related
    extensions in the application’s Info.plist file and code to tell the
    sandbox what you’re doing.</p>
  </blockquote>
  
  <p>My Info.plist defines a document type for <code>.pnd</code> files (the user-chosen file), as well as a document type for <code>.bak</code> files. The entry for the <code>.bak</code> files has, among other properties, the property <code>NSIsRelatedItemType = YES</code>.</p>
  
  <p>I am trying to use Related Items to move an existing file to a backup file (change .pnd suffix to .bak suffix) when the user writes a new version of the .pnd file. The application is sandboxed. I am not proficient with sandboxing.</p>
  
  <p>I am using <code>PasteurOrgManager</code> as the <code>NSFilePresenter</code> class for both the original and backup files:</p>
  
  <pre><code>@interface PasteurOrgData : NSObject &lt;NSFilePresenter&gt;
  . . . .
  @property (readonly, copy) NSURL *primaryPresentedItemURL;
  @property (readonly, copy) NSURL *presentedItemURL;
  @property (readwrite) NSOperationQueue *presentedItemOperationQueue;
  @property (readwrite) NSFileCoordinator *fileCoordinator;
  . . . .
  - (void) doBackupOf: (NSString*) path;
  . . . .
  @end
  </code></pre>
  
  <p>The <code>doBackupOf:</code> method is as follows. Notice that it also sets the <code>NSFilePresenter</code> properties:</p>
  
  <pre><code>- (void) doBackupOf: (NSString*) path
  {
      NSError *error = nil;
      NSString *appSuffix = @".pnd";
  
      NSURL *const pathAsURL = [NSURL URLWithString: [NSString stringWithFormat: @"file://%@", path]];
      NSString *const baseName = [pathAsURL lastPathComponent];
      NSString *const prefixToBasename = [path substringToIndex: [path length] - [baseName length] - 1];
      NSString *const baseNameWithoutExtension = [baseName substringToIndex: [baseName length] - [appSuffix length]];
      NSString *backupPath = [NSString stringWithFormat: @"%@/%@.bak", prefixToBasename, baseNameWithoutExtension];
      NSURL *const backupURL = [NSURL URLWithString: [NSString stringWithFormat: @"file://%@", backupPath]];
  
      // Move backup to trash — I am sure this will be my next challenge
      // (it's a no-op now because there is no pre-existing .bak file)
      [[NSFileManager defaultManager] trashItemAtURL: backupURL
                                    resultingItemURL: nil
                                               error: &amp;error];
  
      // Move file to backup
      primaryPresentedItemURL = pathAsURL;
      presentedItemURL = backupURL;
      presentedItemOperationQueue = [NSOperationQueue mainQueue];
  
      [NSFileCoordinator addFilePresenter: self];
      fileCoordinator = [[NSFileCoordinator alloc] initWithFilePresenter: self];   // error here
      [self backupItemWithCoordinationFrom: pathAsURL
                                        to: backupURL];
      [NSFileCoordinator removeFilePresenter: self];
      fileCoordinator = nil;
  }
  </code></pre>
  
  <p>The <code>backupItemWithCoordinationFrom:</code> method does the heavy lifting, basically:</p>
  
  <pre><code>[fileCoordinator coordinateWritingItemAtURL: from
                                      options: NSFileCoordinatorWritingForMoving
                                        error: &amp;error
                                   byAccessor: ^(NSURL *oldURL) {
                                       [self.fileCoordinator itemAtURL: oldURL willMoveToURL: to];
                                       [[NSFileManager defaultManager] moveItemAtURL: oldURL
                                                                               toURL: to
                                                                               error: &amp;error];
                                       [self.fileCoordinator itemAtURL: oldURL didMoveToURL: to];
                                   }
  </code></pre>
  
  <p>but the code doesn't make it that far. I have traced the code and the URL variables are as I expect, and are reasonable. At the point of "error here" in the above code, where I allocate the File Presenter, I get:</p>
  
  <pre><code>NSFileSandboxingRequestRelatedItemExtension: an error was received from pboxd instead of a token. Domain: NSPOSIXErrorDomain, code: 1
  [presenter] +[NSFileCoordinator addFilePresenter:] could not get a sandbox extension. primaryPresentedItemURL: file:///Users/cope/Me.pnd, presentedItemURL: file:///Users/cope/Me.bak
  </code></pre>
  
  <p>Any help is appreciated.</p>
  
  <p>(I have read related posts <a href="https://stackoverflow.com/questions/11804309/where-can-a-sandboxed-mac-app-save-files">Where can a sandboxed Mac app save files?</a> and <a href="https://stackoverflow.com/questions/22188312/why-do-nsfilepresenter-protocol-methods-never-get-called">Why do NSFilePresenter protocol methods never get called?</a>. I have taken note of several other sandboxing-related posts that don't seem relevant to this issue.)</p>
  
  <p>MacBook Pro, MacOS 10.13.5, XCode Version 9.3 (9E145)</p>