Вот чем я закончил. На самом деле модель представления не очень полезна в этом случае, так как есть только одна строка логики c.
Базовая c структура кода совпадает с вашей MVC пример, за исключением того, что мой код использует RxImagePickerDelegateProxy
вместо GProfilePickAlertVC
. Первый - это обобщенный c делегат, который будет автоматически присоединяться к любому UIImagePickerController системой Rx по мере необходимости.
Функция imagePickerScene(on:modalPresentationStyle:modalTransitionStyle:)
заботится о представлении и отклонении средства выбора изображений. Он действует как координатор.
Функция castOrThrow(_:_:)
является обобщенным c помощником для обработки приведения. Вы можете использовать его повсюду.
final class BasicInfoViewController: UIViewController {
private let profileImageView = GProfileImage(img: #imageLiteral(resourceName: "ic-tab-profile"), renderingMode: .alwaysTemplate)
private let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
let imagePicker = imagePickerScene(
on: self,
modalPresentationStyle: .overFullScreen,
modalTransitionStyle: .crossDissolve
)
pickPhotoButton.rx.tap
.flatMapLatest { Observable.create(imagePicker) }
.compactMap { $0[.editedImage] as? UIImage }
.bind { image in
self.profileImageView.clipsToBounds = true
self.profileImageView.image = image
}
.disposed(by: disposeBag)
}
}
func imagePickerScene(on presenter: UIViewController, modalPresentationStyle: UIModalPresentationStyle? = nil, modalTransitionStyle: UIModalTransitionStyle? = nil) -> (_ observer: AnyObserver<[UIImagePickerController.InfoKey: AnyObject]>) -> Disposable {
return { [weak presenter] observer in
let controller = UIImagePickerController()
if let presentationStyle = modalPresentationStyle {
controller.modalPresentationStyle = presentationStyle
}
if let transitionStyle = modalTransitionStyle {
controller.modalTransitionStyle = transitionStyle
}
presenter?.present(controller, animated: true)
return controller.rx.didFinishPickingMediaWithInfo
.do(onNext: { _ in
presenter?.dismiss(animated: true)
})
.subscribe(observer)
}
}
final class RxImagePickerDelegateProxy: DelegateProxy<UIImagePickerController, UINavigationControllerDelegate & UIImagePickerControllerDelegate>, DelegateProxyType, UINavigationControllerDelegate & UIImagePickerControllerDelegate {
static func currentDelegate(for object: UIImagePickerController) -> (UIImagePickerControllerDelegate & UINavigationControllerDelegate)? {
return object.delegate
}
static func setCurrentDelegate(_ delegate: (UIImagePickerControllerDelegate & UINavigationControllerDelegate)?, to object: UIImagePickerController) {
object.delegate = delegate
}
static func registerKnownImplementations() {
self.register { RxImagePickerDelegateProxy(parentObject: $0, delegateProxy: RxImagePickerDelegateProxy.self) }
}
}
extension Reactive where Base: UIImagePickerController {
var didFinishPickingMediaWithInfo: Observable<[UIImagePickerController.InfoKey: AnyObject]> {
return RxImagePickerDelegateProxy.proxy(for: base)
.methodInvoked(#selector(UIImagePickerControllerDelegate.imagePickerController(_:didFinishPickingMediaWithInfo:)))
.map({ (a) in
return try castOrThrow(Dictionary<UIImagePickerController.InfoKey, AnyObject>.self, a[1])
})
}
}
func castOrThrow<T>(_ resultType: T.Type, _ object: Any) throws -> T {
guard let returnValue = object as? T else {
throw RxCocoaError.castingError(object: object, targetType: resultType)
}
return returnValue
}