Post

Rx 이벤트 처리 문제 풀기

Rx 이벤트 처리 문제 풀기

📌 1번: 버튼 클릭 이벤트 처리

문제 내용

  1. 버튼(UIButton)을 PublishSubject<Void>로 감싸서 Rx 방식으로 클릭 이벤트를 처리하라.
  2. 버튼이 클릭될 때마다 "버튼이 클릭됨"이라는 문자열을 출력하라.
  3. 버튼을 3번 클릭하면 "버튼이 3번 클릭됨"이라는 메시지를 출력하라.

정답 코드

1
2
3
4
5
6
7
8
9
10
11
12
let button = UIButton()
button.rx.tap
    .scan(0) { count, _ in count + 1 }
    .subscribe(onNext: { count in
        if count == 3 {
            print("버튼이 3번 클릭됨")
        } else {
            print("버튼이 클릭됨")
        }
    })
    .disposed(by: disposeBag)

문제 해설

  • .scan(0) { count, _ in count + 1 }클릭 횟수를 누적함.
  • 버튼을 클릭할 때마다 1씩 증가하고, 3번 클릭 시 특정 메시지를 출력함.

📌 2번: 텍스트 입력 감지하기

문제 내용

  1. UITextField를 생성하고, 사용자가 입력한 내용을 감지하라.
  2. 입력할 때마다 입력된 텍스트를 출력하라.
  3. 입력된 텍스트가 "RxSwift"가 되면 "RxSwift 입력 완료"를 출력하라.

정답 코드

1
2
3
4
5
6
7
8
9
10
11
textField.rx.text
    .compactMap { $0 } // 옵셔널 제거
    .subscribe(onNext: { value in
        if value == "RxSwift" {
            print("RxSwift 입력 완료")
        } else {
            print(value)
        }
    })
    .disposed(by: disposeBag)

문제 해설

  • .compactMap { $0 }UITextField.rx.textObservable<String?>이므로 nil 값을 제거해야 한다.
  • 입력된 텍스트가 "RxSwift"가 되면 "RxSwift 입력 완료" 메시지를 출력함.

📌 3번: API 호출 후 UI 업데이트하기

문제 내용

  1. 버튼을 클릭하면 네트워크 요청(Observable<String>)을 수행하는 코드를 작성하라.
  2. 네트워크 요청이 완료되면 결과를 UILabel에 표시하라.
  3. 버튼을 여러 번 클릭해도 동시에 여러 개의 요청이 발생하지 않도록 처리하라.

정답 코드

1
2
3
4
5
6
7
let network: Observable<String> = Observable.just("네트워크 응답")

button.rx.tap
    .withLatestFrom(network)
    .bind(to: label.rx.text)
    .disposed(by: disposeBag)

문제 해설

  • .withLatestFrom(network)버튼을 클릭할 때마다 네트워크의 최신 값 가져옴.
  • .bind(to: label.rx.text)네트워크 응답을 UILabel에 표시함.
  • 이전 요청이 끝나지 않았을 때 중복 요청을 막을 필요가 있으면 flatMapLatest를 사용해야 함.

📌 4번: 중복 네트워크 요청 방지하기

문제 내용

  1. 버튼을 클릭할 때마다 네트워크 요청(Observable<String>)을 수행하라.
  2. 네트워크 요청이 진행 중이면 새로운 요청을 무시하도록 처리하라.
  3. 네트워크 요청이 완료되면 버튼을 다시 클릭할 수 있도록 하라.

정답 코드

1
2
3
4
5
6
7
8
9
func networkRequest() -> Observable<String> {
    return Observable.just("네트워크 응답")
}

button.rx.tap
    .flatMapLatest { networkRequest() }
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

문제 해설

  • .flatMapLatest { networkRequest() }이전 요청이 끝나지 않았을 때, 새로운 요청을 무시함.
  • 버튼 클릭 시 네트워크 요청을 수행하고 응답을 출력함.

📌 5번: 입력 필드와 버튼을 조합하여 검색 요청 만들기

문제 내용

  1. UITextField에 입력된 값을 UIButton을 클릭했을 때만 가져와 출력하라.
  2. 버튼을 클릭하면 입력된 텍스트를 네트워크 요청(Observable<String>)으로 변환하라.
  3. 입력 값이 바뀌더라도, 버튼을 클릭해야만 네트워크 요청이 실행되도록 하라.

정답 코드

1
2
3
4
5
6
7
8
let network = { (query: String) in Observable.just("검색 결과: \(query)") }

button.rx.tap
    .withLatestFrom(textField.rx.text.orEmpty)
    .flatMapLatest { network($0) }
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

문제 해설

  • .withLatestFrom(textField.rx.text.orEmpty)버튼을 클릭할 때, 입력된 텍스트를 가져옴.
  • .flatMapLatest { network($0) }입력된 텍스트를 네트워크 요청으로 변환함.

📌 6번: map 연산자 응용 (문자열 길이 변환)

문제 내용

  1. Observable<[String]>을 생성하여 ["Apple", "Banana", "Cherry"] 배열을 방출하라.
  2. map을 사용하여 각 문자열을 해당 문자열의 길이(Int)로 변환하라.

정답 코드

1
2
3
4
5
Observable.just(["Apple", "Banana", "Cherry"])
    .map { $0.map { $0.count } }
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

문제 해설

  • 배열 내부의 각 문자열을 개별적으로 변환하려면 map을 두 번 사용해야 한다.
  • "Apple" → 5, "Banana" → 6, "Cherry" → 6으로 변환됨.

📌 7번: filter 연산자 응용 (짝수만 필터링)

문제 내용

  1. Observable<[Int]>을 생성하여 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 배열을 방출하라.
  2. filter를 사용하여 짝수만 출력하라.

정답 코드

1
2
3
4
5
Observable.from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
    .filter { $0 % 2 == 0 }
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

문제 해설

  • Observable.from()을 사용하면 배열을 개별 요소로 변환하여 방출할 수 있음.
  • filter를 적용하면 짝수만 출력됨.

📌 8번: scan을 활용한 중복된 검색어 요청 방지

문제 내용

  1. UITextField에서 입력한 텍스트를 실시간으로 감지하라.
  2. 입력된 텍스트가 이전 값과 같다면 요청을 보내지 않도록 처리하라.

정답 코드

1
2
3
4
5
6
7
8
9
10
11
swift
복사
let network = { (query: String) in Observable.just("검색 결과: \(query)") }

textField.rx.text
    .compactMap { $0 }
    .scan("") { before, current in before == current ? before : current }
    .flatMapLatest { network($0) }
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

문제 해설

  • .scan("", { before, current in ... })이전 값과 비교하여 변경된 값만 전달함.
  • .flatMapLatest { network($0) }변경된 값만 네트워크 요청을 보냄.

📌 9번: 버튼 클릭 후, 5초 동안 추가 클릭 방지하기

문제 내용

  1. 버튼 클릭 시 "요청 보냄"을 출력하라.
  2. 클릭 후 5초 동안 버튼을 비활성화하여 추가 클릭을 방지하라.
  3. 5초가 지나면 버튼을 다시 활성화하라.

정답 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
swift
복사
let button = UIButton()
let isEnabled = BehaviorRelay<Bool>(value: true) // 버튼 활성화 상태 관리

button.rx.tap
    .withLatestFrom(isEnabled)
    .filter { $0 } // 버튼이 활성화된 경우에만 실행
    .do(onNext: { _ in isEnabled.accept(false) }) // 클릭 후 비활성화
    .map { "요청 보냄" }
    .subscribe(onNext: {
        print($0)
        isEnabled.accept(true) // 5초 후 버튼 다시 활성화
    })
    .disposed(by: disposeBag)

문제 해설

  • .withLatestFrom(isEnabled)현재 버튼 상태를 확인하고, 활성화된 경우만 실행
  • .do(onNext: { _ in isEnabled.accept(false) })버튼 클릭 후 비활성화(false)로 설정
  • .map { "요청 보냄" }출력값 변환
  • .subscribe(onNext: { ... isEnabled.accept(true) })출력 후 버튼 다시 활성화

📌 10번: filter를 활용한 짝수 필터링

문제 내용

  1. Observable<[Int]>을 생성하여 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 배열을 방출하라.
  2. filter를 사용하여 짝수만 출력하라.

정답 코드

1
2
3
4
5
6
7
swift
복사
Observable.from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
    .filter { $0 % 2 == 0 }
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

문제 해설

  • Observable.from()을 사용하여 배열을 개별 요소로 변환
  • .filter { $0 % 2 == 0 }짝수만 필터링하여 출력
This post is licensed under CC BY 4.0 by the author.