使用带有承诺的UIImagePickerController只能使用一次

时间:2019-12-01 17:27:46

标签: swift uiimagepickercontroller promisekit

我正在重构一个类以使用PromiseKitAwaitKit

我按以下方式致电我的服务-

        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 { }

0 个答案:

没有答案