【问题标题】:Passed in data MVVM RxSwift传入数据 MVVM RxSwift
【发布时间】:2021-07-17 08:42:49
【问题描述】:

我想学习 MVVM RxSwift 的输入输出方法,我想从 textfield 中获取用户名。

我有一个场景,当用户不输入用户名时会出现错误,当用户输入用户名时会出现在 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)

    }

【问题讨论】:

  • 你想对查询做什么?

标签: ios swift mvvm rx-swift


【解决方案1】:

这当然取决于你想对文本做什么,但下面我假设你想发出一个网络请求。但这当然需要了解您的 API 层是什么样的。我也必须在那里做一些假设,但关键是你需要通过它的构造函数/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 { !$0.isEmpty }
            .map { makeEndpoint(using: $0) }
            .flatMap { [api] in
                api.load($0)
            }
            .share()

        let missingName = input.getFollowers
            .withLatestFrom(input.username)
            .compactMap { $0.isEmpty ? "Please enter a username. We need to know who to look for" : nil }

        let errorMessage = Observable.merge(
            api.error.map { $0.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 { $0.isEmpty ? "Please enter a username. We need to know who to look for" : nil }
            .asDriver(onErrorJustReturn: "")

        let username = input.getFollowers
            .withLatestFrom(input.username)
            .filter { !$0.isEmpty }
            .asDriver(onErrorJustReturn: "")

        return Output(errorMessage: errorMessage, username: username)
    }
}

这里的关键是,您需要为视图控制器想要订阅的每个输出提供一个驱动程序。

【讨论】:

  • 没错我以后想调用一个api,但是在这个问题中我只想返回一个错误消息并获取字符串用户名。一个呈现错误,另一个推送到 viewController。
  • 谢谢丹尼尔,直到现在让我感到困惑的是。我可以返回单个字符串,以便我可以在 viewController 中切换结果,这样我就可以呈现或推送。所以在 RxSwift 中,它必须将 errorMessage 和输出中的查询分开。顺便说一句,它就像一个魅力
  • 可以使用enum 做到这一点,但首先使用 MVVM 的目的是分别定义每个动态行为,以便它可以驱动视图附在。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-24
  • 2021-08-24
  • 1970-01-01
  • 1970-01-01
  • 2020-03-21
  • 1970-01-01
  • 2017-05-28
相关资源
最近更新 更多