일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- Tuist
- UIViewControllerTransitioningDelegate
- ViewBuilder
- url 관찰
- 상단 탭바
- SwiftUI
- ios
- DataBinding
- Side Menu
- 개발자 면접
- pod install
- DevelopmentRegion
- List
- swift #swift keychain #keychain 사용법
- development language
- oberve url
- url 추적
- detect url
- UIPresentationController
- scrolling tab
- swift
- GeometryReader
- Android
- transformation.map
- notifychanged
- convert base64
- Swift Package Manager
- 기존 앱
- base64 변환
- 스크롤 탭
- Today
- Total
버그 잡이
RxSwift - 버튼 활성화 상태 제어하기 #CombineLatest #Binding 본문
RxSwift 를 활용하면 버튼의 활성화 상태를 보다 쉽게 제어할 수 있습니다.
이를 위해서는 먼저 RxSwift의 두 가지 Operator에 대해서 이해할 필요가 있습니다.
Combine Latest
2개 이상의 Observable을 합쳐서 발행해줍니다.
근데 그 패턴이 좀 독특해서 그림으로 이해할 필요가 있습니다.
combineLatest는 다음과 같은 특징이 있습니다.
1. 합쳐지는 observable 들이 각각 최초 발행해야 result가 생성된다.
2. 둘 다 onCompleted 되어야 onComplete된다.
3. error는 하나만 발생해도 error를 전달한다.
(코드로 살펴보겠습니다.)
let bag = DisposeBag()
enum MyError: Error {
case error
}
let greetings = PublishSubject<String>()
let languages = PublishSubject<String>()
Observable.combineLatest(greetings, languages){ first, second
-> String in
return "\(first) \(second)"
}
.subscribe{ print($0) }
.disposed(by: bag)
greetings.onNext("hi") // nothing
languages.onNext("world") // hi world
greetings.onNext("hello") // hello world
languages.onError(MyError.error) // error
Binding
binding은 rxcocoa에서 지원하는 기능으로 UI-Binding을 가능하게 해줍니다.
즉, 데이터와 View를 binding해서 데이터가 변할때마다 이를 View에 반영해줄 수 있습니다,
이는 UI와 관련이 있기 때문에 main-thread에서 실행되고 error 이벤트를 받지 않습니다.
(error 이벤트를 받게 되면 앱이 종료되겠죠?)
기존에 RxSwfit를 활용해서 textField의 input을 view에 바로 반영하려면 아래와 같이 코드를 작성 해야합니다.
valueField.rx.text
.subscribe(onNext: {[weak self] str in
self?.valueLabel.text = str})
그리고 위의 코드는 완벽하지 않습니다.
왜냐하면 View의 최신화는 main-thread에서 해줘야합니다.
따라서 DispatchQueue로 감싸주거나 observeOn(MainScheduler.instance)로 스레드를 설정 해줘야 합니다.
바인딩을 활용하면 보다 간결하게 코드를 작성할 수 있습니다.
valueField.rx.text
.bind(to: valueLabel.rx.text)
.disposed(by: disposeBag)
버튼 활성화 여부 제어
오늘의 하이라이트 RxSwift를 활용한 버튼 활성화 여부 변경하기 입니다.
로그인 화면에서 아이디와 비밀번호 field에 공백에 없어야 "로그인 버튼" 을 활성화 시켜야 하는 경우가 있습니다.
RxSwift를 활용하면 보다 깔끔하고 직관적으로 이를 처리할 수 있습니다.
var a = BehaviorSubject<Bool>()
var b = BehaviorSubject<Bool>()
idField.rx.text
.subscribe(onNext: {
if $0 == "" {
a.onNext(false)
} else {
a.onNext(true)
}
})
pwdField.rx.text
.subscribe(onNext: {
if $0 == "" {
b.onNext(false)
} else {
b.onNext(true)
}
})
Observable.combineLatest(a,b) {$0 && $1}
.bind(to: loginButton.rx.isEnabled)
.disposed(by: disposeBag)
위 코드에서
a는 아이디 입력 textField가 공백인지 check하는 observable
b는 비밀번호 입력 textField가 공백인지 check하는 observable
입니다.
이 둘의 상태를 combineLatest로 묶어줌으로써 하나의 상태라도 변경될 때마다 observable이 발행되고
loginButton.rx.isEnabled = a && b 로 최신화 되는 것입니다.
'RxSwift' 카테고리의 다른 글
RxSwift - bind() 말고 drive()를 써보는건 어때요? (2) | 2020.11.29 |
---|---|
RxSwift - subscribe시 onNext를 명시해줘야 하는 이유 (0) | 2020.10.26 |
RxSwift - Dispose & DisposeBag (0) | 2020.10.01 |
RxSwift로 tableView 구현하기 (0) | 2020.09.20 |
RxSwift - tap으로 addTarget을 대체해보자. (1) | 2020.09.17 |