मैं आरएक्सस्विफ्ट के लिए नया हूं और एमवीवीएम इनपुट आउटपुट दृष्टिकोण के साथ शीर्षक राज्यों के रूप में करने का प्रयास कर रहा हूं।

मैं निम्नलिखित करने के लिए सबसे अच्छा तरीका नहीं समझ सकता।

  1. सबमिट बटन टैप किए जाने पर फ़ोन नंबर टेक्स्ट फ़ील्ड मानों को मान्य करें
  2. अगर फोन नम्बर टेक्स्टफिल्ड अमान्य है और क्लाइंट साइड एरर फेंक दें तो अलामोफायर रिक्वेस्ट को सबमिट होने से रोकें
  3. लोडिंग होने पर डिस्प्ले इंडिकेटर दिखाएं। यह अभी सबसे कम महत्वपूर्ण है

ध्यान देने योग्य कुछ बातें।

  • इस समय फ़ोन नंबर टेक्स्ट को ट्रैक करने वाला कुछ भी नहीं है
  • मैं सबमिट बटन को तब तक अक्षम नहीं करना चाहता जब तक कि फॉर्म मान्य न हो जैसा कि सभी उदाहरणों में देखा गया है।

यहाँ मेरा व्यू कंट्रोलर है

import UIKit
import RxSwift
import RxCocoa

class SplashViewController: BaseViewController {

    // MARK: – View Variables

    @IBOutlet weak var phoneNumberTextField: UITextField!
    @IBOutlet weak var phoneNumberBackgroundView: UIView!
    @IBOutlet weak var submitButton: BaseButton!
    @IBOutlet weak var scrollView: UIScrollView!
    @IBOutlet weak var separatorView: UIView!
    @IBOutlet weak var countryCodeButton: UIButton!
    @IBOutlet weak var parentVerticalStackView: UIStackView!

    // MARK: – View Model & RxSwift Setup

    private let disposeBag = DisposeBag()
    private let viewModel: SplashMVVM = SplashMVVM()

    // MARK: – View lifecycle

    override func viewDidLoad() {
        super.viewDidLoad()

        // RxSwift handling
        setupViewModelBinding()
        setupCallbacks()

    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        navigationController?.setNavigationBarHidden(true, animated: true)
    }

    // MARK: – RxSwift Handling

    private func setupViewModelBinding() {

        submitButton.rx.controlEvent(.touchUpInside)
            .bind(to: viewModel.input.submit)
            .disposed(by: disposeBag)

    }

    private func setupCallbacks() {

        viewModel.output.success.asObservable()
            .filter { $0 != nil }
            .observeOn(MainScheduler())
            .subscribe({ _ in
                self.pushVerifyPhoneNumberViewController()
            })
            .disposed(by: disposeBag)

        viewModel.output.error.asObservable()
            .filter { $0 != nil }
            .observeOn(MainScheduler())
            .subscribe({ _ in
                SwiftMessages.show(.error, message: "There was an error. Please try again.")
            })
            .disposed(by: disposeBag)

    }

    // MARK: – Navigation

    func pushVerifyPhoneNumberViewController() {

        let viewController = VerifyPhoneNumberViewController.fromStoryboard("Authentication")

        self.navigationController?.pushViewController(viewController, animated: true)

    }

}

यहाँ मेरा दृश्य मॉडल है।

import Foundation
import RxSwift
import RxCocoa
import Alamofire

final class SplashMVVM: InputOutputModelType {


let input: SplashMVVM.Input
let output: SplashMVVM.Output

var submitSubject = PublishSubject<Void>()

struct Input {
    let submit: AnyObserver<Void>
}

struct Output {
    let success: Observable<VerifyMobilePhone?>
    let error: Observable<Error?>
}    

init() {

    input = Input(submit: submitSubject.asObserver())

    let request = Alamofire.request(VerifyMobileRouter.post("+16306996540")).responseDecodableRx(VerifyMobilePhone.self)

    let requestData = submitSubject.flatMapLatest {
        request
    }

    let success = requestData.map { $0.value ?? nil }

    let error = requestData.map { $0.error ?? nil }

    output = Output(
        success: success,
        error: error
    )

}

}

यहां वह है जो मैंने जुटाया।

final class SplashMVVM: InputOutputModelType {

let input: SplashMVVM.Input
let output: SplashMVVM.Output

var submitSubject = PublishSubject<Void>()
var phoneNumberSubject = PublishSubject<String>()

struct Input {
    let phoneNumber: AnyObserver<String>
    let submit: AnyObserver<Void>
}

struct Output {
    let validationError: Observable<String>
    let success: Observable<VerifyMobilePhone>
    let error: Observable<Error>
}

init() {

    input = Input(phoneNumber: phoneNumberSubject.asObserver(), submit: submitSubject.asObserver())

    let request = submitSubject.asObservable().withLatestFrom(phoneNumberSubject.asObservable()).filter {
        $0.isValidPhoneNumber(region: "US")
    }.flatMap { number in
        Alamofire.request(VerifyMobileRouter.post(number)).responseDecodableRx(VerifyMobilePhone.self)
    }.share()

    let validationError = submitSubject.asObservable().withLatestFrom(phoneNumberSubject.asObservable()).filter {
        !$0.isValidPhoneNumber(region: "US")
    }.map { _ in
        "This phone number is invalid"
    }

    let success = request.filter { $0.isSuccess }.map { $0.value! }

    let error = request.filter { $0.isFailure }.map { $0.error! }

    output = Output(
        validationError: validationError,
        success: success,
        error: error
    )

}

}

नियंत्रक परिवर्तन देखें…

   private func setupViewModelBinding() {
        submitButton.rx.controlEvent(.touchUpInside).bind(to: viewModel.input.submit).disposed(by: disposeBag)
        phoneNumberTextField.rx.text.orEmpty.bind(to: viewModel.input.phoneNumber).disposed(by: disposeBag)
    }

    private func setupCallbacks() {

        viewModel.output.validationError.bind { string in
            SwiftMessages.show(.error, message: string)
        }.disposed(by: disposeBag)

        viewModel.output.success.bind { verifyMobilePhone in
            self.pushVerifyPhoneNumberViewController()
        }.disposed(by: disposeBag)

        viewModel.output.error.bind { error in
            SwiftMessages.show(.error, message: "There was an error. Please try again.")
        }.disposed(by: disposeBag)

    }
1
morcutt 12 जिंदा 2019, 22:21

1 उत्तर

सबसे बढ़िया उत्तर

आप करीब हैं, आप अपने व्यू मॉडल में इनपुट के रूप में फोन नंबर टेक्स्ट खो रहे हैं।

struct SplashInput {
    let phoneNumber: Observable<String>
    let submit: Observable<Void>
}

struct SplashOutput {
    let invalidInput: Observable<Void>
    let success: Observable<VerifyMobilePhone>
    let error: Observable<Error>
}

extension SplashOutput {
    init(_ input: SplashInput) {
        let request: Observable<Event<VerifyMobilePhone>> = input.submit.withLatestFrom(input.phoneNumber)
            .filter { $0.isValidPhoneNumber }
            .flatMap { number in
                Alamofire.request(VerifyMobileRouter.post(number)).responseDecodableRx(VerifyMobilePhone.self)
                    .materialize()
            }
            .share()

        invalidInput = input.submit.withLatestFrom(input.phoneNumber)
            .filter { $0.isValidPhoneNumber == false }

        success = request
            .map { $0.element }
            .filter { $0 != nil }
            .map { $0! }

        error = request
            .map { $0.error }
            .filter { $0 != nil }
            .map { $0! }
    }
}

आपके SplashViewController के पास होगा:

override func viewDidLoad() {
    super.viewDidLoad()
    let input = SplashInput(
        phoneNumber: phoneNumberTextField.rx.text.orEmpty.asObservable(),
        submit: submitButton.rx.tap.asObservable()
    )
    let viewModel = SplashOutput(input)
    viewModel.invalidInput
        .bind {
            SwiftMessages.show(.invalid, message: "You entered an invalid number. Please try again.")
       }
        .disposed(by: bag)

    viewModel.success
        .bind { [unowned self] verifyMobilePhone in
            self.pushVerifyPhoneNumberViewController(verifyMobilePhone)
        }
        .disposed(by: bag)

    viewModel.error
        .bind { error in
            SwiftMessages.show(.error(error), message: "There was an error. Please try again.")
        }
 }

(जो आपने पहले ही लिखा है, उसके साथ मैंने कुछ स्वतंत्रता ली है, लेकिन उपरोक्त को समझ में आना चाहिए।)

1
Daniel T. 12 जिंदा 2019, 23:08