Swift 6,“图像”导致数据争用?

问题描述 投票:0回答:1

我有一个图像选择器结构,我用它来拍摄照片并将其存储为列表,但是由于 Swift 6 严格并发,我一生都无法让它工作。

这是原始结构

struct ImagePickerView: UIViewControllerRepresentable {
    class Coordinator: NSObject, UINavigationControllerDelegate, UIImagePickerControllerDelegate, PHPickerViewControllerDelegate {
        var parent: ImagePickerView

        init(_ parent: ImagePickerView) {
            self.parent = parent
        }

        // Handle image picker for camera capture
        func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
            if let image = info[.originalImage] as? UIImage {
                if let imageData = image.jpegData(compressionQuality: 0.6) {
                    parent.imageList.append(ImageData(
                        _id: "\(UUID())",
                        imageData: imageData
                    ))
                }
            }
            picker.dismiss(animated: true)
        }

        // Handle picker for selecting from library
        func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
            picker.dismiss(animated: true)

            guard let provider = results.first?.itemProvider else { return }
            if provider.canLoadObject(ofClass: UIImage.self) {
                provider.loadObject(ofClass: UIImage.self) { image, _ in
                    DispatchQueue.main.async {
                        if let imageData = (image as? UIImage)?.jpegData(compressionQuality: 0.6) {
                            self.parent.imageList.append(ImageData(
                                _id: "\(UUID())",
                                imageData: imageData
                            ))
                        }
                    }
                }
            }
        }
    }

    @Binding var imageList: [ImageData]
    @Binding var isCamera: Bool

    func makeCoordinator() -> Coordinator {
        return Coordinator(self)
    }

    func makeUIViewController(context: Context) -> UIViewController {
        if isCamera {
            // Camera access using UIImagePickerController
            let imagePicker = UIImagePickerController()
            imagePicker.sourceType = .camera
            imagePicker.delegate = context.coordinator
            return imagePicker
        } else {
            // Photo Library using PHPickerViewController
            var config = PHPickerConfiguration()
            config.selectionLimit = 1
            config.filter = .images

            let picker = PHPickerViewController(configuration: config)
            picker.delegate = context.coordinator
            return picker
        }
    }

    func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
}

在选择器函数中,if let imageData = (image as? UIImage)?,图像被标记为,

Sending 'image' risks causing data races.

Task-isolated 'image' is captured by a main actor-isolated closure. main actor-isolated uses in closure may race against later nonisolated uses.

我正在努力了解如何修复此错误,我尝试将调度队列作为任务运行 { @MainActor in } 但这导致 self.parent 说发送 self 会导致数据争用。

swift xcode swiftui swift6
1个回答
0
投票

您正在尝试使用 GCD 解决 Swift 并发隔离问题,这通常不是一个好主意。

loadObject 完成处理程序需要

Sendable
一致性,因为它可以跨并发域传递。这也意味着所有捕获的值必须符合
Sendable

请参阅SE-0302了解更多详情。

您的

Coordinator
已经绑定到
MainActor
,因为您已经在
ImagePickerView
中声明了它,它通过
UIViewControllerRepresentable
接收 actor 绑定。这意味着
Coordinator
已经符合
Sendable

所以你不需要做这方面的任何事情。您所要做的就是调整完成处理程序中的调用:

// Handle picker for selecting from library
func picker(
    _ picker: PHPickerViewController,
    didFinishPicking results: [PHPickerResult]
) {
    picker.dismiss(animated: true)

    guard let provider = results.first?.itemProvider, provider.canLoadObject(ofClass: UIImage.self) else {
        return
    }

    provider.loadObject(ofClass: UIImage.self) { image, _ in
        guard let imageData = (image as? UIImage)?.jpegData(compressionQuality: 0.6) else {
            return
        }

        Task { @MainActor in
            self.parent.imageList.append(ImageData(
                _id: UUID().uuidString,
                imageData: imageData
            ))
        }
    }
}

请注意,这会捕获完成处理程序中的“self”以及其中的任务。 如果您想防止这种情况或有取消机制,则必须相应地添加它。但是,这不是您实际问题的一部分。

© www.soinside.com 2019 - 2024. All rights reserved.