如何在RxSwift中设置属性并从UIAlertController获取回调



我有一个ViewModelType来绑定UIViewController&ViewModel。

import Foundation
protocol ViewModelType {
associatedtype Input
associatedtype Output

func transform(input: Input) -> Output
}

HomeViewModel符合ViewModelType并定义所需的输入和输出,然后它根据输入返回输出。

为了简单起见,我删除了存储库,并总是为syncData任务返回失败。

import Foundation
import RxSwift
import RxCocoa
class HomeViewModel: ViewModelType {
struct Input {
let syncData: Driver<Void>
}

struct Output {
let message: Driver<String>
}

func transform(input: Input) -> Output {
let fetching = input.syncData.flatMapLatest { _ -> Driver<String> in
return Observable<String>.from(optional: "Choose below options to proceed") // This message will be returned by server.
.delay(.seconds(1), scheduler: MainScheduler.instance)
.asDriverOnErrorJustComplete()
}
return Output(message: fetching)
}
}

我有一个带字符串的提醒活页夹。

UIAlertController在单击重试按钮时有一个重试按钮。我想从HomeViewModelInput调用syncData。我该怎么做?

import UIKit
import RxSwift
import RxCocoa
class HomeViewController: UIViewController {
private let disposeBag = DisposeBag()

var viewModel = HomeViewModel()

override func viewDidLoad() {
super.viewDidLoad()

let viewDidAppear = rx.sentMessage(#selector(UIViewController.viewDidAppear(_:)))
.mapToVoid()
.asDriverOnErrorJustComplete()

// How to merge viewWillAppear & alert for callback of retry button?
let input = HomeViewModel.Input(syncData: viewDidAppear)
let output = viewModel.transform(input: input)

output.message.drive(alert)
.disposed(by: disposeBag)
}
var alert: Binder<String> {
return Binder(self) { (vc, message) in
let alert = UIAlertController(title: "Sync failed!",
message: message,
preferredStyle: .alert)
let okay = UIAlertAction(title: "Retry", style: .default, handler: { _ in
// how to call syncData of Input?
})
let dismiss = UIAlertAction(title: "Dismiss",
style: UIAlertAction.Style.cancel,
handler: nil)
alert.addAction(okay)
alert.addAction(dismiss)
vc.present(alert, animated: true, completion: nil)
}
} 
}

当您将非RxCode转换为RxCode时(如使UIAlertAction成为反应式(,以及当您必须创建一个循环时(如将视图模型的输出反馈回其自己的输入(,有两种情况应该使用Subject

如果你发现自己经常这样做,那么你可能需要考虑制作多视图模型。

您还会注意到,我将警报的创建作为自己的、独立的协调器功能。这样它就可以在多个地方使用。如果您愿意,您可以对传递到flatMapFirst中的闭包执行相同的操作。

class HomeViewModel {
struct Input {
let syncData: Observable<Void>
let retry: Observable<Void>
}
struct Output {
let message: Observable<String>
}
func transform(input: Input) -> Output {
let fetching = Observable.merge(input.syncData, input.retry)
.flatMapLatest { _ -> Observable<String> in
return Observable<String>.from(optional: "Choose below options to proceed") // This message will be returned by server.
.delay(.seconds(1), scheduler: MainScheduler.instance)
}
return Output(message: fetching)
}
}
class HomeViewController: UIViewController {
private let disposeBag = DisposeBag()
var viewModel = HomeViewModel()
override func viewDidLoad() {
super.viewDidLoad()
let viewDidAppear = rx.sentMessage(#selector(UIViewController.viewDidAppear(_:)))
.mapToVoid()
let retry = PublishSubject<Void>()
let input = HomeViewModel.Input(syncData: viewDidAppear, retry: retry.asObservable())
let output = viewModel.transform(input: input)
output.message
.flatMapFirst { [weak self] (message) -> Observable<Void> in
let (alert, trigger) = createAlert(message: message)
self?.present(alert, animated: true)
return trigger
}
.subscribe(retry)
.disposed(by: disposeBag)
}
}
func createAlert(message: String) -> (UIViewController, Observable<Void>) {
let trigger = PublishSubject<Void>()
let alert = UIAlertController(title: "Sync failed!",
message: message,
preferredStyle: .alert)
let okay = UIAlertAction(title: "Retry", style: .default, handler: { _ in
trigger.onNext(())
trigger.onCompleted()
})
let dismiss = UIAlertAction(title: "Dismiss",
style: UIAlertAction.Style.cancel,
handler: nil)
alert.addAction(okay)
alert.addAction(dismiss)
return (alert, trigger)
}

首先,您应该使用一些协调器来调用推送/呈现控制器。并制作代表Alert的函数。

例如:

class Router {
private let rootViewController: UIViewController
let retryAction = PublishSubject<Void>()
func showGalleryAlert() {
let alert = UIAlertController(title: "Your Title", message: "Your Message", preferredStyle: .alert)
let settings = UIAlertAction(title: "Name Action", style: .default) { _ in
// send here your action to PublishSubject
self.retryAction.send()
}
let cancel = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
alert.addAction(cancel)
alert.addAction(settings)
rootViewController.present(alert, animated: true)
}}

然后你需要将这个路由器插入到你的ViewModel中,并监听这个PublishSubject。

或者你可以使用Single/Maybe函数,这里有一个如何使用它的小例子:

public func openList() -> Maybe<Void> {          
return .create { observer -> Disposable in
let alert = UIAlertController(title: "Your Title", message: "YourMessage", preferredStyle: .alert)
let settings = UIAlertAction(title: "Name Action", style: .default) { _ in
// send here your action
observer.send() 
}
let cancel = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
alert.addAction(cancel)
alert.addAction(settings)
rootViewController.present(alert, animated: true)
return Disposables.create {
DispatchQueue.main.async {
vc.dismiss(animated: true, completion: nil)
}
}
}
}

并通过ViewModel进行处理。

附言:您应该在ViewModel中的输入上使用Subject,而不是Drivers。驱动程序必须仅用于输出等视图

相关内容

  • 没有找到相关文章

最新更新