【问题标题】:Passing data MVVM and RxSwift传递数据 MVVM 和 RxSwift
【发布时间】:2020-03-13 10:55:04
【问题描述】:

我目前正在学习 MVVM 和 RxSwift。在我的主视图控制器中,我有一张我想传入的图像。我成功地使用了 mvc 和 RxSwift,但是因为 MVVM 对我来说是新的。我不知道如何在 MVVM 中实现。这是我的代码。

// This is the work version MVC RxSwift
    class GProfilePickAlertVC: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {

    private let selectedSubjectPhoto = PublishSubject<UIImage>()
    var selectedPhoto: Observable<UIImage> {
        return selectedSubjectPhoto.asObservable()
    }

    func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        if let editedImage     = info[.editedImage] as? UIImage {
            self.selectedSubjectPhoto.onNext(editedImage)
            dismiss(animated: true, completion: nil)
        }
        dismiss(animated: true, completion: nil)
    }
}

    class BasicInfoViewController: UITableViewController {
    let profileImageView    = GProfileImage(img: #imageLiteral(resourceName: "ic-tab-profile"), renderingMode: .alwaysTemplate)

    @objc private func handlePickPhoto() {
        let pickPhotoVC = GProfilePickAlertVC()
        pickPhotoVC.selectedPhoto.subscribe(onNext: { image in
            self.profileImageView.clipsToBounds = true
            self.profileImageView.image = image
            }).disposed(by: disposeBag)
        pickPhotoVC.modalPresentationStyle = .overFullScreen
        pickPhotoVC.modalTransitionStyle = .crossDissolve
        present(pickPhotoVC, animated: true)
    }
}

// This is my MVVM setup
    struct BasicInfoViewModel {

    let selectedImage: BehaviorRelay<UIImage>
}

    class BasicInfoViewController: UITableViewController {

    let disposeBag          = DisposeBag()

    var BasicInfoViewModel: BasicInfoViewModel!
}

【问题讨论】:

    标签: mvvm uiimage rx-swift


    【解决方案1】:

    这就是我最终的结果。在这种情况下,视图模型真的没什么可做的,因为只有一行逻辑。

    代码的基本结构与您的 MVC 示例相同,只是我的代码使用 RxImagePickerDelegateProxy 而不是 GProfilePickAlertVC。前者是一个通用委托,它会根据需要由 Rx 系统自动附加到任何 UIImagePickerController。

    imagePickerScene(on:modalPresentationStyle:modalTransitionStyle:) 函数负责显示和关闭图像选择器。它充当协调器。

    castOrThrow(_:_:) 函数是处理强制转换的通用助手。你可以在任何地方使用它。

    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
    }
    

    【讨论】:

    • 嘿,谢谢@DanielT。所以并不是所有的属性都需要在视图模型中创建,我想学习 MVVM 和 RxSwift。有什么推荐吗?
    • 查看github.com/danielt1263/RxEarthquake 以获得良好的样本。另外,加入 slack 社区rxslack.herokuapp.com 并阅读整个#rxmvvm 频道。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-24
    • 2020-03-21
    • 1970-01-01
    • 2021-08-24
    • 1970-01-01
    • 1970-01-01
    • 2015-01-20
    相关资源
    最近更新 更多