swift/swift 공부

[RxSwift] UIView에 tap event 추가하기 ( rx.event의 형태)

isak(이삭) 2024. 2. 15. 01:10

UIView에 tap gesture를 추가하게 된 이유)

 

앱의 SettingView를 구현하게 되었는데 TableView를 사용하지 않고 공통된 UIView를 생성하고 VC에서 그 UIView를 생성해서 UI를 그려야겠다고 생각했다.

 

이유는,

1. 설정에 많은 리스트가 필요하지 않아서 모델링을 해서 뷰를 그려야하는게 조금 번거로울 수 있겠다.

2. 프로젝트의 다른 부분에서 UITableViewDiffableDataSource로 tableview를 완성하기 위해 수많은 시행착오를 겪으면서 tableview를 그리는 것에 정신이 혼미하다.

 

이 2가지 이유에 의해서 이번 SettingView에는 간단하게 UIView에 tapGesture를 추가해서 rx로 바인딩해주기로 결정했다.

(이 글을 작성하면서 드는 생각은, 이용약관, 개인정보 처리 방침도 들어와야하는데 테이블뷰가 더 적합했을지도 . . ? 확장성의 측면을 고려하지 못했던거 같다. 아니면 UIButton으로 해서 rx.tap 으로 )

 

+) 글을 다 작성하고 추가하는 글

이해하고 썼다고 생각했는데 한참을 공식문서의 형태를 찾아보고 Observable에 대해서 찾아보고 그랬던 것 같다.

이유 있는 코드, 이해하고 작성하는 코드를 추구하는데 정말 정말 어렵다. 


클릭 이벤트가 발생하지 않는 UI Component에 Tap Gesture 추가

 

일단 실행 화면을 보고 오시죠.

일단 UIView로 SettingView를 만들고, VC에서 UIView인 객체를 2개 만들어서 뷰를 구성했다.

 

1. ViewController에 UIView 생성

public final class DefaultSettingsViewController: UIController {
    
    private let basicAlarmSetting: SettingView = {
        let view = SettingView(
            iconName: "alarm",
            title: "알람 설정",
            rightTitle: "",
            isHiddenArrowRight: false
        )
        return view
    }()
}

 

2. Tap Event를 감지하고 전달할 Rx 프로퍼티 생성

// in VC
private let defaultAlarmSetBtn = PublishSubject<Void>()

 

3. UIView에 tapGesture 주입 및 RxCocoa의 rx.event를 통해 touch event 전달

// VC
func bind() {
	let tapGesture = UITapGestureRecognizer()
    basicAlarmSetting.addGestureRecognizer(tapGesture)
        
    tapGesture.rx.event // tapGesture를 관찰이 가능한 ControlEvent의 형태로 만듦
        .map({ _ in }) // ControlEvent 형태를 Observable 형태로 변형
        .bind(to: defaultAlarmSetBtn) // PublishSubject에 데이터 전달
        .disposed(by: disposeBag)

    _ = viewModel.transform(input: .init(
        defaultAlarmTapEvent: defaultAlarmSetBtn.asObservable()) // ViewModel의 input에 전달하여 뷰 이동시킴
        // PublishSubject는 그 자체로도 Observable 형태라서 asObservable로 꼭 해주어야하는 것은 아니지만 
        // asObservable()을 해주는 것으로 더 명시적으로 사용 가능함!
    )
}

 

🧐 rx.event가 뭐야 ? 

라고 하신다면 공식 문서를 봐볼까요 ?

 

rx.event는 Observable의 한 형태인 ControlEvent로 데이터를 Return 합니다.

( + Observable은 값을 관찰만 가능함. ControlEvent은 Observable의 한 형태이기 때문에 값을 관찰할 수 있음)

 

❓ControlEvent 는 뭔데 ? 어떻게 Observable을 전달할 수 있어? 라고 물으신다면 

ControlEvent의 형태
ControlEventType의 형태
ControlEventType이 상속을 채택한 ObservableType의 형태
ObservableType이 상속을 채택한 ObservableConvertibleType의 형태

 

ControlEvent이 상속받은 것들을 타고 타고 넘어가다보면, 최종적으로 ObservableConvertibleType을 볼 수 있다.

ObservableConvertibleType의 단어를 끊어서 보면 Observable + Convertible + Type.

말 그대로 Observable로 converting이 가능한 type 이시다 !!

 

결론 : ControlEventrx.Observable을 상속받았기 때문에 Observable과 동일한 형태로 데이터를 리턴할 수 있는 것이다 !

 

하지만,

ControlEvent를 Observable로 데이터를 리턴할 수 있다고 했지만 bind를 통해서 데이터 전달을 해주기 위해서는 타입을 ControlEvent가 아닌 Observable 타입으로 변경해주어야 합니다!!

 

+

Observable 타입으로 변경을 해주어야 하는 이유는,

bind를 통해 tapGesture의 데이터를 전달해줘야하는데 전달받을 그릇(defaultAlarmBtn)의 타입 형태랑 같아야 전달이 가능하기 때문.

 

tapGesture.rx.event 👉 ControlEvent type

.map 👉 Observable type

.bind(to: defaultAlarmBtn) 👉 Observable type

 

 

정리해봅시다!

 

1. tapGesture 생성 후 [RxCocoa의] rx.event를 통해 ControlEvent형태로 데이터 전달

2. ControlEvent를 Observable로 사용하기 위해서 .map 을 사용하여 Observable 형태로 데이터 타입 변경

3. 동일한 Observable 형태로 데이터를 전달해주는 것은 bind

4. 메모리 누수를 막기 위해 disposebag 

 

5. bind를 통해 받은 데이터를 사용하는 곳에 주입

 


 

혹시 잘못된 부분이 있으면 지식 나눔해주신다면 너무 감사할 것 같습니다 !!