Handling Main Actor-Isolated Values with `PHPhotoLibrary` in Swift 6

Hello,

I’m encountering an issue with the PHPhotoLibrary API in Swift 6 and iOS 18. The code I’m using worked fine in Swift 5, but I’m now seeing the following error:

Sending main actor-isolated value of type '() -> Void' with later accesses to nonisolated context risks causing data races

Here is the problematic code:


  Button("Save to Camera Roll") {
      saveToCameraRoll()
  }

...

private func saveToCameraRoll() {
    guard let overlayFileURL = mediaManager.getOverlayURL() else {
        return
    }
    
    Task {
        do {
            let status = await PHPhotoLibrary.requestAuthorization(for: .addOnly)
            guard status == .authorized else {
                return
            }
            
            try await PHPhotoLibrary.shared().performChanges({
                if let creationRequest = PHAssetCreationRequest.creationRequestForAssetFromVideo(atFileURL: overlayFileURL) {
                    creationRequest.creationDate = Date()
                }
            })
            await MainActor.run {
                saveSuccessMessage = "Video saved to Camera Roll successfully"
            }
        } catch {
            print("Error saving video to Camera Roll: \(error.localizedDescription)")
        }
    }
}

Problem Description:

  • The error message suggests that a main actor-isolated value of type () -> Void is being accessed in a nonisolated context, potentially leading to data races.
  • This issue arises specifically at the call to PHPhotoLibrary.shared().performChanges.

Questions:

  1. How can I address the data race issues related to main actor isolation when using PHPhotoLibrary.shared().performChanges?
  2. What changes, if any, are required to adapt this code for Swift 6 and iOS 18 while maintaining thread safety and actor isolation?
  3. Are there any recommended practices for managing main actor-isolated values in asynchronous operations to avoid data races?

I appreciate any points or suggestions to resolve this issue effectively.

Thank you!

Answered by Dirk-FU in 803644022

This works in my code:

try await PHPhotoLibrary.shared().performChanges{@Sendable in
...
}

but be sure to only capture sendable values in the closure.

Accepted Answer

This works in my code:

try await PHPhotoLibrary.shared().performChanges{@Sendable in
...
}

but be sure to only capture sendable values in the closure.

Handling Main Actor-Isolated Values with `PHPhotoLibrary` in Swift 6
 
 
Q