传入数据 MVVM RxSwift
Passed in data MVVM RxSwift
我想学习带输入输出方法的 MVVM RxSwift,我想从文本字段中获取用户名。
我有一个场景,当用户不输入用户名时,它会出现错误,当用户输入用户名时,它会出现在 viewController。
这是我迷茫的时候。我收到错误消息并成功显示错误,但是如何在我的 viewModel 中捕获查询并将数据传递给 viewController。
这就是我设置 searchViewModel 的方式
protocol ViewModelType {
associatedtype Input
associatedtype Output
func transform(input: Input) -> Output
}
class SearchViewModel: ViewModelType {
// MARK: Binding
struct Input {
let searchText: Observable<String>
let validate: Observable<Void>
}
struct Output {
let username: Driver<String>
}
func transform(input: Input) -> Output {
let username = input.validate
.withLatestFrom(input.searchText)
.map { query in
if query.isEmpty {
return "Please enter a username. We need to know who to look for"
} else {
return query
}
}.asDriver(onErrorJustReturn: "")
return Output(username: username)
}
}
这是我在 SearchViewController 中的 viewDidLoad
let searchTextField = GFTextField()
let calloutBtn = GFButton(backgroundColor: .systemGreen, title: "Get followers")
private let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
setupImageView()
setupTextfield()
setupCalloutBtn()
let input = SearchViewModel.Input(
searchText: searchTextField.rx.text.orEmpty.asObservable(),
validate: calloutBtn.rx.tap.asObservable())
let output = viewModel.transform(input: input)
output.username.drive { [weak self] username in
guard let self = self else { return }
self.presentGFAlertOnMainThread(title: "Empty Username", message: username, buttonTitle: "Dismiss")
}.disposed(by: disposeBag)
}
当然这取决于你想对文本做什么,但下面我假设你想发出网络请求。但当然,这需要了解您的 API 层的外观。我也必须在那里做一些假设,但关键是你需要通过它的 constructor/init 方法将你的 API 层注入你的视图模型。
像这样:
class SearchViewModel: ViewModelType {
struct Input {
let username: Observable<String>
let getFollowers: Observable<Void>
}
struct Output {
let errorMessage: Driver<String>
let followers: Driver<[Follower]>
}
let api: API
init(api: API) {
self.api = api
}
func transform(input: Input) -> Output {
let followersResponse = input.getFollowers
.withLatestFrom(input.username)
.filter { ![=10=].isEmpty }
.map { makeEndpoint(using: [=10=]) }
.flatMap { [api] in
api.load([=10=])
}
.share()
let missingName = input.getFollowers
.withLatestFrom(input.username)
.compactMap { [=10=].isEmpty ? "Please enter a username. We need to know who to look for" : nil }
let errorMessage = Observable.merge(
api.error.map { [=10=].localizedDescription },
missingName
)
.asDriver(onErrorJustReturn: "")
let followers = followersResponse
.asDriver(onErrorJustReturn: [])
return Output(errorMessage: errorMessage, followers: followers)
}
}
-- 编辑 --
如果您只想将非空文本字段推送回视图控制器,那么它将如下所示:
class SearchViewModel: ViewModelType {
struct Input {
let username: Observable<String>
let getFollowers: Observable<Void>
}
struct Output {
let errorMessage: Driver<String>
let username: Driver<String>
}
func transform(input: Input) -> Output {
let errorMessage = input.getFollowers
.withLatestFrom(input.username)
.compactMap { [=11=].isEmpty ? "Please enter a username. We need to know who to look for" : nil }
.asDriver(onErrorJustReturn: "")
let username = input.getFollowers
.withLatestFrom(input.username)
.filter { ![=11=].isEmpty }
.asDriver(onErrorJustReturn: "")
return Output(errorMessage: errorMessage, username: username)
}
}
这里的关键是视图控制器想要订阅的每个输出都需要一个驱动程序。
我想学习带输入输出方法的 MVVM RxSwift,我想从文本字段中获取用户名。
我有一个场景,当用户不输入用户名时,它会出现错误,当用户输入用户名时,它会出现在 viewController。
这是我迷茫的时候。我收到错误消息并成功显示错误,但是如何在我的 viewModel 中捕获查询并将数据传递给 viewController。
这就是我设置 searchViewModel 的方式
protocol ViewModelType {
associatedtype Input
associatedtype Output
func transform(input: Input) -> Output
}
class SearchViewModel: ViewModelType {
// MARK: Binding
struct Input {
let searchText: Observable<String>
let validate: Observable<Void>
}
struct Output {
let username: Driver<String>
}
func transform(input: Input) -> Output {
let username = input.validate
.withLatestFrom(input.searchText)
.map { query in
if query.isEmpty {
return "Please enter a username. We need to know who to look for"
} else {
return query
}
}.asDriver(onErrorJustReturn: "")
return Output(username: username)
}
}
这是我在 SearchViewController 中的 viewDidLoad
let searchTextField = GFTextField()
let calloutBtn = GFButton(backgroundColor: .systemGreen, title: "Get followers")
private let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
setupImageView()
setupTextfield()
setupCalloutBtn()
let input = SearchViewModel.Input(
searchText: searchTextField.rx.text.orEmpty.asObservable(),
validate: calloutBtn.rx.tap.asObservable())
let output = viewModel.transform(input: input)
output.username.drive { [weak self] username in
guard let self = self else { return }
self.presentGFAlertOnMainThread(title: "Empty Username", message: username, buttonTitle: "Dismiss")
}.disposed(by: disposeBag)
}
当然这取决于你想对文本做什么,但下面我假设你想发出网络请求。但当然,这需要了解您的 API 层的外观。我也必须在那里做一些假设,但关键是你需要通过它的 constructor/init 方法将你的 API 层注入你的视图模型。
像这样:
class SearchViewModel: ViewModelType {
struct Input {
let username: Observable<String>
let getFollowers: Observable<Void>
}
struct Output {
let errorMessage: Driver<String>
let followers: Driver<[Follower]>
}
let api: API
init(api: API) {
self.api = api
}
func transform(input: Input) -> Output {
let followersResponse = input.getFollowers
.withLatestFrom(input.username)
.filter { ![=10=].isEmpty }
.map { makeEndpoint(using: [=10=]) }
.flatMap { [api] in
api.load([=10=])
}
.share()
let missingName = input.getFollowers
.withLatestFrom(input.username)
.compactMap { [=10=].isEmpty ? "Please enter a username. We need to know who to look for" : nil }
let errorMessage = Observable.merge(
api.error.map { [=10=].localizedDescription },
missingName
)
.asDriver(onErrorJustReturn: "")
let followers = followersResponse
.asDriver(onErrorJustReturn: [])
return Output(errorMessage: errorMessage, followers: followers)
}
}
-- 编辑 --
如果您只想将非空文本字段推送回视图控制器,那么它将如下所示:
class SearchViewModel: ViewModelType {
struct Input {
let username: Observable<String>
let getFollowers: Observable<Void>
}
struct Output {
let errorMessage: Driver<String>
let username: Driver<String>
}
func transform(input: Input) -> Output {
let errorMessage = input.getFollowers
.withLatestFrom(input.username)
.compactMap { [=11=].isEmpty ? "Please enter a username. We need to know who to look for" : nil }
.asDriver(onErrorJustReturn: "")
let username = input.getFollowers
.withLatestFrom(input.username)
.filter { ![=11=].isEmpty }
.asDriver(onErrorJustReturn: "")
return Output(errorMessage: errorMessage, username: username)
}
}
这里的关键是视图控制器想要订阅的每个输出都需要一个驱动程序。