使用异步 PHPicker 选择图像后执行操作

Perform action after picking image with async PHPicker

问题

要执行BitwiseAND(UIImage1, UIImage2)运算这是OpenCV框架的功能。 UIImage1 已经出现在 MainVC 中:

@IBOutlet weak var presentedImage: UIImageView!

因此,只要用户需要,就必须另外选择 UIImage2。 值得一提:

@IBOutlet weak var presentedImage: UIImageView!

也使用相同的 PHPicker 选择,如 UIImage2

目前的解题思路...

创建了 2 个标志:

@IBOutlet weak var presentedImage: UIImageView!

或为了“按位的目的”。

这是旗帜:

private var isBitwisePick: Bool = false
 private var bitwiseOperationType: OperationTypes.ControllerTypes.BitwiseTypes?
 enum ControllerTypes{
 /*...*/
    enum BitwiseTypes{ case AND,NOR,XOR,OR }
/*.../
}

尝试处理用户的图片选择

/* This is switch-case of callback from other viewcontroller.
In our case only this one matters
*/
case .BITWISE_VC(let bitwise):
               
            self.isBitwisePick = true //Pick image for "Bitwise purpose"
            self.bitwiseOperationType = bitwise // determines type of Bitwise 
 
            // config and present PHPicker
            var config = PHPickerConfiguration()
            config.filter = .images
            config.selectionLimit = 1
            let picker = PHPickerViewController(configuration: config)
            picker.delegate = self
            self.present(picker, animated: true)

PHPickerViewControllerDelegate

extension MainViewController:  PHPickerViewControllerDelegate{
    func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
        dismiss(animated: true)
        print("test before async \(self.isBitwisePick)")
        if let itemProvider = results.first?.itemProvider, itemProvider.canLoadObject(ofClass: UIImage.self){
            let previousImage = self.presentedImage.image
            itemProvider.loadObject(ofClass: UIImage.self){ [weak self] image, error in
                DispatchQueue.main.async { [self] in
                    guard let self = self, let image = image as? UIImage, self.presentedImage.image == previousImage else {
                        return
                    }
                    print("Im in async \(self.isBitwisePick)")
                    if(self.isBitwisePick){
                        switch self.bitwiseOperationType{
                            case .AND:
                                self.presentedImage.image = OpenCVWrapper.bitwiseAND(self.presentedImage.image, with: image)
                                break
                            default:
                                print("the same for XOR OR NOR")
                            break
                        }
                    }
                    else{ self.presentedImage.image = image }
                }
            }
            self.isBitwisePick = false
        }
    }
}

同线

print(" test before async (self.isBitwisePick)")

我可以看到,该标志已更改,其值为 true

然而...行:

print("Im in async (self.isBitwisePick)") prints value : false

我刚开始使用 swift,阅读了一些有关 DispatchQueue 或 DispatchGroup 等解决方案的帖子和文档...但我无法解决问题。 这就是为什么我要寻求您的帮助和提示。 感谢您的宝贵时间:)

你的数据结构应该是这样的

private var firstImage: UIImage?
private var secondImage: UIImage?

然后你可以覆盖 setter 或应用一些其他机制,比如

private var firstImage: UIImage? { didSet { reevaluateImagesSet() } }
private var secondImage: UIImage? { didSet { reevaluateImagesSet() } }

private func reevaluateImagesSet() {
    imageView1.image = firstImage
    imageView2.image = secondImage

    if let firstImage = firstImage, let secondImage = secondImage {
        applyCombinedImage(firstImage, secondImage)
    }
}

private func applyCombinedImage(_ firstImage: UIImage, _ secondImage: UIImage) {
    // do the bitwise operation of yours in here
}

现在唯一的问题是如何定义要设置的图像。您可以使用一个布尔标志或创建一个自定义 class 使得事情像这样:

   @IBAction private func selectFirstImagePressed() {
        let picker = MyPicker(controller: self)
        self.currentPicker = picker
        picker.selectImage { image in
            self.firstImage = image
        }
   }

   @IBAction private func selectSecondImagePressed() {
        let picker = MyPicker(controller: self)
        self.currentPicker = picker
        picker.selectImage { image in
            self.secondImage = image
        }
   }

此 class MyPicker 然后对应于 PHPickerViewControllerDelegate 并在提供的闭包中仅对 return 图像实施逻辑。我希望你在实施它时不会遇到任何问题。它主要是提取您已有的代码。

问题出在线路上

 self.isBitwisePick = false

在您的 didFinishPicking() 函数中。该行将在调用 itemProvider.loadObject(ofClass:) 函数的完成处理程序之前执行。然后,当您在完成处理程序中检查 isBitwisePick 时,它将是错误的。您应该将该行移到完成处理程序中。

编辑:

Matic Oblak 关于将第一张图像和第二张图像保存到数据模型中的建议很好。从图像视图中取出原始图像的方式似乎不对,因为在按位操作之后,图像视图将包含经过处理的图像,不是吗? (另外,一般来说,您不应该将数据存储在视图对象中。视图对象用于向用户显示信息并收集用户的输入,而不是存储数据。这就是模型的用途。(我建议您阅读关于 MVC 设计模式。还有很多其他可供选择的设计模式,但与 MVC 一样,几乎所有设计模式都没有将视图视为存储数据的地方。)