apple/RxSwift, ReactorKit

iOS RxDelegateProxy 만들어보기 #1

lgvv 2022. 1. 12. 15:12

iOS RxDelegateProxy 만들어보기

Delegate를 RxSwift에 통합하여 사용하기 위해 Proxy를 만드는 방법을 학습 

 



연관포스팅

 

 

샘플코드

RxSwiftDelegateExample.zip
0.68MB



목차

  • Protocol과 Delegate 개념 간단 정리
  • RxDelegateProxy GuideLine


Protocol과 Delegate 개념 간단 정리

RxDelegateProxy를 만들어보기 위해서는 Delegate와 Protocol에 대해서 간단하게 정리

아래는 테이블 뷰 예시코드에서 VC2에 있는 Delegate를 VC1에 위임할 수 있음.

  • 이렇게 할 경우 보다시피 VC2에서 Delegate의 구현체를 VC1에 위임하여 구현체를 구현하지 않아도 에러가 나지 않음.

 

class VC1: UIViewController, UITableViewDelegate {
    var tableViewVC1: UITableView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        tableViewVC1.delegate = self // [CASE #1] self(VC1)에 있는 delegate 기능을 tableViewVC1이 사용하겠다.
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { }
}

class VC2: UIViewController {
    var tableViewVC2: UITableView!
    let vc1 = VC1()
    
    override func viewDidLoad() {
         super.viewDidLoad()
         tableViewVC2.delegate = vc1 // [CASE #2] vc1에 있는 delegate 기능(함수)를 tableViewVC2에서 사용하겠다.
         tableViewVC2.dataSource = vc1
    }
}



RxDelegateProxy GuideLine

ViewController가 2개가 존재하여 두개의 객체 사이에 이벤트를 Proxy를 통해 만들어진 것을 통해 통신하는 간단한 예제.

 

스토리보드를 활용하여 작업

스토리보드



 

🟠 ViewController.swift

//
//  ViewController.swift
//  RxSwiftDelegateExample
//
//  Created by lgvv0908 on 2022/01/12
//

import UIKit
import RxSwift
import RxCocoa

final class ViewController: UIViewController, InputViewControllerDelegate {
    
    private var disposeBag = DisposeBag()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let storyBoard = UIStoryboard(name: "Main", bundle: .main)
        guard let viewController = storyBoard.instantiateViewController(
            withIdentifier: "InputViewController"
        ) as? InputViewController else { return }
        
        viewController.rx.rx_deleagte.setForwardToDelegate(self, retainDelegate: false)
        
        viewController.rx.rx_sendString
            .bind(to: inputLabel.rx.text)
            .disposed(by: disposeBag)
        
        openButton.rx.tap
            .throttle(.seconds(1), scheduler: MainScheduler.instance) // 버튼 클릭 후 1초동안 동일 이벤트 방출 안함
            .subscribe(onNext: { [weak self] _ in
                guard let self else { return }
                self.present(viewController, animated: true, completion: nil)
            }).disposed(by: disposeBag)
        
        
        openSubjectButton.rx.tap
            .bind { [weak self] in
                guard let self else { return }
                self.present(viewController, animated: true, completion: nil)
            }.disposed(by: disposeBag)
        
        viewController.inputStringSubject
            .bind(to: inputLabel.rx.text)
            .disposed(by: disposeBag)
    }
    
    // MARK: - UIComponents
    
    @IBOutlet weak var inputLabel: UILabel!
    @IBOutlet weak var openButton: UIButton!
    @IBOutlet weak var openSubjectButton: UIButton!
    
}

 
🟠 InputViewController.swift

//
//  InputViewController.swift
//  RxSwiftDelegateExample
//
//  Created by lgvv0908 on 2022/01/12
//  Copyright © 2020 swieeft. All rights reserved.
//

import UIKit
import RxSwift
import RxCocoa

class InputViewController: UIViewController {

    @IBOutlet weak var textField: UITextField!
    @IBOutlet weak var confirmButton: UIButton!
    @IBOutlet weak var confirmSubjectButton: UIButton!

    weak var delegate: InputViewControllerDelegate?
    
    var disposeBag = DisposeBag()

    var inputStringSubject = PublishSubject<String>() // 여기서 서브젝트를 갖고 있음
    var inputString: Observable<String> { // 프로퍼티인데, inputStringSubject값을 Observable<String>값으로 받고 있음
        return inputStringSubject.asObservable()
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        confirmButton.rx.tap
            .throttle(.seconds(1), scheduler: MainScheduler.asyncInstance)
            .subscribe(onNext: { [weak self] _ in
                guard let string = self?.textField.text else { return }

                self?.dismiss(animated: true, completion: {
                    self?.delegate?.sendString?(string: string) // 프로토콜로 데이터 전달함
                })
            })
            .disposed(by: disposeBag)

        confirmSubjectButton.rx.tap
            .debug("confirmSubjectButton")
            .throttle(.seconds(1), scheduler: MainScheduler.asyncInstance)
            .subscribe(onNext: { [weak self] _ in
                guard let string = self?.textField.text else { return }

              // self?.inputStringSubject.onNext(string) // 서브젝트로 방출함

                self?.dismiss(animated: true, completion: {
                    self?.inputStringSubject.onNext(string) // 서브젝트로 방출함
                    print("string -> \(string)")
//                    self?.inputStringSubject.onCompleted()
                })
            })
            .disposed(by: disposeBag)
        

        textField.rx.controlEvent(.editingDidEndOnExit)
            .debug("editingDidEndOnExit")
            .subscribe(onNext: { [weak self] _ in
                self?.view.endEditing(true)
            })
            .disposed(by: disposeBag)
    }
}

 

'apple > RxSwift, ReactorKit' 카테고리의 다른 글

RxSwift ch 18. Table & Collection views  (0) 2022.01.18
Extension Reactive (RxSwift)  (1) 2022.01.12
iOS RxStarScream 총정리  (0) 2022.01.12
RxSwift 06 RxDataSources  (0) 2021.08.19
Ch13. Intermediate RxCocoa  (0) 2021.08.12