传递数据 MVVM 和 RxSwift
Posted
技术标签:
【中文标题】传递数据 MVVM 和 RxSwift【英文标题】:Passing data MVVM and 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!
【问题讨论】:
【参考方案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 频道。以上是关于传递数据 MVVM 和 RxSwift的主要内容,如果未能解决你的问题,请参考以下文章
使用 rxSwift 中的 tableView 单元将数据从视图模型传递到视图控制器
使用委托从iOS中的ViewModel传递数据到UI的任何替代方法?