Передача значения в ViewModel из ViewController с RxSwift - PullRequest
1 голос
/ 13 июня 2019

У меня есть сцена в приложении, в которую меня попросили внести изменения.

Я не очень знаком с RxSwift, поэтому, пожалуйста, прости меня, если это очевидно.

Мой контроллер просмотра отображает WKWebView, который содержит форму входа. Когда пользователь заполняет форму, возвращается свойство, которое я сейчас распечатываю в WKNavigationDelegate.

Что я хотел бы сделать, это передать это свойство моему oauthService, которое существует как зависимость внутри моего ViewModel.

Я мог бы создать метод в модели, такой как

  func passPropToServie(_ prop: String) {
        // do something
    }

и просто вызовите это из контроллера представления, но я не уверен, правильно ли это, или каков способ rxswift.

Еще раз извините, это приложение, которое я подбираю, поэтому с исходным кодом я все еще смиряюсь.

LoginCoordinator

import UIKit
import RxCocoa
import RxSwift

class LoginCoordinator: BaseCoordinator<()> {
    typealias Dependencies = HasOAuthService

    private let window: UIWindow
    private let dependencies: Dependencies

    init(window: UIWindow, dependencies: Dependencies) {
        self.window = window
        self.dependencies = dependencies
    }

    override func start() -> Observable<()> {
        let viewController = LoginViewController()
        let avm: Attachable<LoginViewModel> = .detached(dependencies)
        let viewModel = viewController.attach(wrapper: avm)

        viewModel.loginURL.drive(onNext: { login in
            viewController.handle(login?.url)
        }).disposed(by: viewController.disposeBag)

        window.rootViewController = viewController
        window.makeKeyAndVisible()

        return viewModel.isLoggedIn
            .asObservable()
            .filter { $0 }
            .map { _ in return }
    }
}

LoginViewController

import UIKit
import WebKit
import RxCocoa
import RxSwift

class LoginViewController: UIViewController, ViewModelAttaching {

    let disposeBag = DisposeBag()

    var viewModel: Attachable<LoginViewModel>!
    var bindings: LoginViewModel.Bindings {
        return LoginViewModel.Bindings()
    }

    private var requestURL: URL?

    lazy var webView: WKWebView = {
        let webConfiguration = WKWebViewConfiguration()
        webConfiguration.dataDetectorTypes = [.all]
        let webView = WKWebView(frame: .zero, configuration: webConfiguration)
        webView.navigationDelegate = self
        webView.allowsBackForwardNavigationGestures = false
        return webView
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func loadView() {
        view = webView
    }

    func bind(viewModel: LoginViewModel) -> LoginViewModel {

        return viewModel
    }

    func handle(_ url: URL?) {
        guard let url = url else { return }
        requestURL = url
        webView.load(URLRequest(url: url))
    }
}

extension LoginViewController: WKNavigationDelegate {
    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        if let url = navigationAction.request.url, url.scheme == "homedev", url.valueOf("code") != nil {
            print(url)
        }
        decisionHandler(.allow)
    }
}

LoginViewModel

import RxSwift
import RxCocoa

final class LoginViewModel: ViewModelType {

    typealias Dependency = HasOAuthService

    let isLoggedIn: Driver<Bool>
    let loginURL: Driver<URLComponents?>

    struct Bindings { }

    init(dependency: Dependency, bindings: Bindings) {

        isLoggedIn = dependency.oauthService.currentUser
            .map { user in return user == true }
            .asDriver(onErrorJustReturn: false)

        loginURL = dependency.oauthService.loginURL
            .map { $0 }
            .asDriver(onErrorJustReturn: nil)
    }
}

1 Ответ

1 голос
/ 13 июня 2019

Все зависит от того, как далеко в кроличью нору вы хотите пойти.Rx предназначен для замены всех различных способов, которыми мы обычно помещаем данные в объекты.Поэтому, если вы доведите это до крайности, у вас не будет никаких обратных вызовов, @IBActions или делегатов;и вы не будете назначать var или вызывать функцию с данными, просто чтобы использовать данные в другом классе.Есть обертки, которые позволят вам исключить функцию делегата в вашем LoginViewController, например.

Я предполагаю, что структура Bindings предназначена для ввода в модель представления, если это так, то я быскорее всего, добавьте Observable в привязках и тему публикации в контроллере представления.Вызов onNext по теме публикации будет воспринят в модели представления через привязку.

Вы могли бы извлечь пользу из прочтения этой статьи: Интеграция RxSwift в ваш мозг и базу кода

...