使用异步 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 个标志:
- 第一个检查,如果当前使用 PHPicker 选择的图像是
@IBOutlet weak var presentedImage: UIImageView!
或为了“按位的目的”。
这是旗帜:
private var isBitwisePick: Bool = false
- 第二个“标志”确定要执行的按位类型(AND XOR NOR OR)
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 一样,几乎所有设计模式都没有将视图视为存储数据的地方。)
问题
要执行BitwiseAND(UIImage1, UIImage2)运算这是OpenCV框架的功能。 UIImage1 已经出现在 MainVC 中:
@IBOutlet weak var presentedImage: UIImageView!
因此,只要用户需要,就必须另外选择 UIImage2。 值得一提:
@IBOutlet weak var presentedImage: UIImageView!
也使用相同的 PHPicker 选择,如 UIImage2
目前的解题思路...
创建了 2 个标志:
- 第一个检查,如果当前使用 PHPicker 选择的图像是
@IBOutlet weak var presentedImage: UIImageView!
或为了“按位的目的”。
这是旗帜:
private var isBitwisePick: Bool = false
- 第二个“标志”确定要执行的按位类型(AND XOR NOR OR)
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 一样,几乎所有设计模式都没有将视图视为存储数据的地方。)