我正在重构一个类以使用PromiseKit
和AwaitKit
。
我按以下方式致电我的服务-
imagePicker.present(from: view.editProfilePictureButton, options: options)
.done { res in print(res.image) }
.catch { err in print(err.localizedDescription) }
但是,我页面上有3个按钮可以触发图像上传。此过程仅适用于第一次尝试。
现在,在没有任何反应的情况下进行任何尝试,我都可以选择图像,执行所有步骤,但是承诺永远都无法解决。
我怀疑这行是要做的事情
private let (promise, seal) = Promise<ImagePickerPayload>.pending()
我相信,当我发出第一个请求时,这个承诺不再pending
,因此,随后的触发尝试从未实现/被拒绝。
如何处理这种情况并确保尝试解析一个值?
import UIKit
import PromiseKit
import AwaitKit
struct ImagePickerPayload {
enum ActionType {
case update, remove
}
var action: ActionType
var image: UIImage?
}
struct ImagePickerOptions: OptionSet {
static let showRemove = ImagePickerOptions(rawValue: 1)
let rawValue: Int
}
protocol ImagePickerType: AnyObject {
var presentationController: UIViewController? { get set }
func present(from source: UIView, options: ImagePickerOptions) -> Promise<ImagePickerPayload>
}
final class ImagePicker: NSObject {
weak var presentationController: UIViewController?
private let pickerController: UIImagePickerController
private let (promise, seal) = Promise<ImagePickerPayload>.pending()
init(pickerController: UIImagePickerController = UIImagePickerController()) {
self.pickerController = pickerController
super.init()
self.pickerController.delegate = self
self.pickerController.allowsEditing = true
self.pickerController.mediaTypes = ["public.image"]
}
func present(from source: UIView, options: ImagePickerOptions) -> Promise<ImagePickerPayload> {
return async { [presentationController, promise, seal, weak self] in
let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
if options.contains(.showRemove) {
alertController.addAction(.init(title: "Remove Current Image", style: .destructive, handler: { _ in
seal.fulfill(.init(action: .remove, image: nil))
}))
}
if let action = self?.createAction(for: .camera, text: "Take Photo") {
alertController.addAction(action)
}
if let action = self?.createAction(for: .photoLibrary, text: "Choose From Library") {
alertController.addAction(action) }
if UIDevice.current.userInterfaceIdiom == .pad {
alertController.popoverPresentationController?.sourceView = source
alertController.popoverPresentationController?.sourceRect = source.bounds
alertController.popoverPresentationController?.permittedArrowDirections = [.left, .right]
}
alertController.addAction(.init(title: "Cancel", style: .cancel, handler: nil))
DispatchQueue.main.async {
presentationController?.present(alertController, animated: true, completion: nil)
}
let result: ImagePickerPayload = try! await(promise)
return result
}
}
private func createAction(for type: UIImagePickerController.SourceType, text: String) -> UIAlertAction? {
guard UIImagePickerController.isSourceTypeAvailable(type) else { return nil }
return .init(title: text, style: .default) { [pickerController, presentationController] _ in
pickerController.sourceType = type
presentationController?.present(pickerController, animated: true, completion: nil)
}
}
private func pickerController(_ controller: UIImagePickerController, didSelect image: UIImage?) {
seal.fulfill(.init(action: .update, image: image))
controller.dismiss(animated: true, completion: nil)
}
}
extension ImagePicker: UIImagePickerControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
guard let image = info[.editedImage] as? UIImage else { return pickerController(picker, didSelect: nil) }
pickerController(picker, didSelect: image)
}
}
extension ImagePicker: UINavigationControllerDelegate { }
extension ImagePicker: ImagePickerType { }