title: Missing image metadata when saving updated image into PhotoKit
body: <p>I am having an issue updating an image's metadata and saving that back to the Photos library. Everything <em>works</em> except that the image metadata after it's altered has missing entries that were there before and I am not getting any errors manipulating the image or executing the photos library change block. Also, the dictionary before it's written back into the image looks like the original plus my dictionary in the debugger.  </p>
  
  <p>My questions are:</p>
  
  <ol>
  <li>What am I doing wrong that would cause rewriting the existing
  properties back with additional data to wipe out what is there? </li>
  <li>Is there better, more canonical way to do this? It seems like a lot of mechanics to update some meta data in an image. It just seems like
  What Everyone Else Is Doing.</li>
  </ol>
  
  <p><strong>EDIT:</strong></p>
  
  <p>Before the save all the Exif and Tiff values are present. This is the entirety of the metadata after the save to photos using the code below:</p>
  
  <pre><code>["PixelHeight": 2448, "PixelWidth": 3264, "{Exif}": {
  ColorSpace = 1;
  PixelXDimension = 3264;
  PixelYDimension = 2448;}, "Depth": 8, "ProfileName": sRGB IEC61966-2.1, "Orientation": 1, "{TIFF}": {
  Orientation = 1;}, "ColorModel": RGB, "{JFIF}": {
  DensityUnit = 0;
  JFIFVersion =     (
      1,
      0,
      1
  );
  XDensity = 72;
  YDensity = 72;}]
  </code></pre>
  
  <p>The code, all in Swift 3, testing on iOS 10.1</p>
  
  <p>The basic workflow is:</p>
  
  <pre><code>    // Get a mutable copy of the existing Exif meta
      let mutableMetaData = getMutableMetadataFrom(imageData: data)
  
      // Check to see if it has the {GPS} entry, if it does just exit.
      if let _ = mutableMetaData[kCGImagePropertyGPSDictionary as String] {
         callback(imageAsset, true, nil)
         return
      }
  
      // Add the {GPS} tag to the existing metadata
      let clLocation = media.location!.asCLLocation()
      mutableMetaData[kCGImagePropertyGPSDictionary as String] =
         clLocation.asGPSMetaData()
  
      // Attach the new metadata to the existing image
      guard let newImageData = attach(metadata: mutableMetaData, toImageData: data) else {
              callback(imageAsset, false, nil)
              return
      }
  
      let editingOptions = PHContentEditingInputRequestOptions()
      imageAsset.requestContentEditingInput(with: editingOptions) { editingInput, info in
          guard let editingInput = editingInput else { return }
          let library = PHPhotoLibrary.shared()
          let output = PHContentEditingOutput(contentEditingInput: editingInput)
          output.adjustmentData = PHAdjustmentData(formatIdentifier: "Project", formatVersion: "0.1",
                                                   data: "Location Adjustment".data(using: .utf8)!)
          do {
              try newImageData.write(to: output.renderedContentURL, options: [.atomic])
          } catch {
              callback(imageAsset, false, error)
              return
          }
  
          library.performChanges({
              let changeRequest = PHAssetChangeRequest(for: imageAsset)
              changeRequest.location = clLocation
              changeRequest.contentEditingOutput = output
  
          }, completionHandler: { success, error in ... ...
  </code></pre>
  
  <p>The helper methods to the workflow are:</p>
  
  <pre><code>func attach(metadata: NSDictionary, toImageData imageData:Data) -&gt; Data? {
  
      guard
          let imageDataProvider = CGDataProvider(data: imageData as CFData),
          let cgImage = CGImage(jpegDataProviderSource: imageDataProvider, decode: nil,
                                shouldInterpolate: true, intent: .defaultIntent),
          let newImageData = CFDataCreateMutable(nil, 0),
          let type = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType,
                                                           "image/jpg" as CFString, kUTTypeImage),
          let destination = CGImageDestinationCreateWithData(newImageData,
                                                             (type.takeRetainedValue()), 1, nil) else {
  
              return nil
          }
  
      CGImageDestinationAddImage(destination, cgImage, metadata as CFDictionary)
      CGImageDestinationFinalize(destination)
  
      guard
          let newProvider = CGDataProvider(data: newImageData),
          let newCGImage = CGImage(jpegDataProviderSource: newProvider, decode: nil,
                                   shouldInterpolate: false, intent: .defaultIntent) else {
  
              return nil
      }
  
      return UIImageJPEGRepresentation(UIImage(cgImage: newCGImage), 1.0)
  }
  
  func getMutableMetadataFrom(imageData data : Data) -&gt; NSMutableDictionary {
  
      let imageSourceRef = CGImageSourceCreateWithData(data as CFData, nil)
      let currentProperties = CGImageSourceCopyPropertiesAtIndex(imageSourceRef!, 0, nil)
      let mutableDict = NSMutableDictionary(dictionary: currentProperties!)
  
      return mutableDict
  }
  </code></pre>
  
  <p>Also the <code>asGPSMetaData</code> is an extension on <code>CLLocation</code> than looks a Swift 3 version of <a href="https://gist.github.com/rsattar/b06060df7ea293b398d1" rel="noreferrer">this Gist</a></p>