Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |
Tags
- 리펙토링
- 리팩토링
- Xcode
- ios
- collectionview
- uitableview
- rxswift
- UICollectionView
- clean architecture
- swift documentation
- Human interface guide
- SWIFT
- RxCocoa
- tableView
- 리펙터링
- Protocol
- Refactoring
- MVVM
- swiftUI
- ribs
- HIG
- 클린 코드
- Clean Code
- map
- 애니메이션
- 스위프트
- uiscrollview
- combine
- Observable
- UITextView
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[iOS - swift] RxSwiftExt로 syntactic sugar 코딩하기 본문
* syntactic sugar: 기능은 동일하지만 장황하지 않게 코딩하는것
RxSwiftExt
- RxSwiftExt는 RxSwift에 연산자를 extension하여 여러가지 유용한 연산자를 제공
- 보통 RxSwift에서 extension으로 직접 custom하여 연산자를 정의하여 사용해도 되지만, 오픈소스를 사용하면 처음 오는 개발자도 해당 오픈 소스를 알고 있다면 쉽게 바로 사용할 수 있는 장점이 존재
- RxSwiftExt를 알고 있으면 장황한 코드들을 더욱 단순하게 처리할 수 있는 점이 존재
RxSwift 연산자를 선언적으로 사용하기
- '무엇'이 아닌 '어떻게'에 대한 내용을 선언적으로 표현하는게 핵심
- 피해야하는 코드
- keypath를 사용할 수 있지만, 클로저를 사용하는 코드
- 쓸모없는 map { } 중괄호를 사용하는 코드
- 한 줄로 표현할 수 있는 것들을 두 줄 이상으로 표현하는 코드
RxSwiftExt의 유용한 연산자
- framework 준비
target 'ExRxSwiftExt' do
use_frameworks!
pod 'RxSwift'
pod 'RxSwiftExt'
end
- unwrap()
- compactMap과 클로저를 사용하지 않고 unwrap()으로 바로 사용
private func unwrap() {
let observable = Observable.of(Int?(1),2,nil,4,5)
// before
observable
.compactMap { $0 }
.debug()
.subscribe()
.disposed(by: disposeBag)
// after
observable
.unwrap()
.debug()
.subscribe()
.disposed(by: disposeBag)
}
- retry()
private func retry() {
let observable = Observable<Int>.error(NSError(domain: "error", code: 1))
// .immediate: 즉시 반복
observable
.retry(.immediate(maxCount: 2))
.debug()
.subscribe()
.disposed(by: disposeBag)
// .delayed: n초 후 반복
observable
.retry(.delayed(maxCount: 2, time: 3)) // 3초 후 한번 더 시도
.debug()
.subscribe()
.disposed(by: disposeBag)
// .customTimerDelayed: retry 시간 커스텀 + 클로저
observable
.retry(.customTimerDelayed(maxCount: 2, delayCalculator: { count in
return .seconds(3)
}))
.debug()
.subscribe()
.disposed(by: disposeBag)
// .exponentialDelayed: 지수 증가 (시간 - initial^mutiplier)
observable
.retry(.exponentialDelayed(maxCount: 2, initial: 3, multiplier: 2)) // 9초 후 한번 더 시도
.debug()
.subscribe()
.disposed(by: disposeBag)
}
- pairwise()
- 이전에 방출된 값을 알 수 있기 때문에 매우 유용
private func pairwise() {
let observable = Observable.of(true, false)
// before x
// after
observable
.pairwise()
.map { $0 == $1 }
.subscribe()
.disposed(by: disposeBag)
}
- ignore()
private func ignore() {
let observable = Observable.of(-1,1,2,3,4,5)
// before
observable
.filter { $0 != -1 && $0 != 1 }
.debug()
.subscribe()
.disposed(by: disposeBag)
// after
observable
.ignore(-1, 1)
.debug()
.subscribe()
.disposed(by: disposeBag)
}
- mapTo()
private func mapToVoid() {
let observable = Observable.just(1)
// before
observable
.map { _ in () }
.subscribe()
.disposed(by: disposeBag)
// after
observable
.mapTo(())
.subscribe()
.disposed(by: disposeBag)
}
- count { condition }
private func count() {
let observable = Observable.of(1,2,3,4,5)
// before
var count = 0
observable
.filter { $0 % 2 == 0 }
.do(onNext: { _ in count += 1 })
.subscribe()
.disposed(by: disposeBag)
// after
observable
.count { $0 % 2 == 0 }
.subscribe()
.disposed(by: disposeBag)
}
RxSwiftExt의 기타 연산자
- not()
private func toggle() {
let observable = Observable.just(false)
// before
observable
.map { !$0 }
.subscribe()
.disposed(by: disposeBag)
// after
observable
.not()
.subscribe()
.disposed(by: disposeBag)
}
- and()
private func and() {
let observable = Observable.of(true, false)
// before
observable
.pairwise()
.map { $0 == $1 }
.subscribe()
.disposed(by: disposeBag)
// after
observable
.and()
.debug()
.subscribe()
.disposed(by: disposeBag)
}
- catchErrorJustComplete
private func catchErrorJustComplete() {
let observable = Observable<Int>.error(NSError(domain: "error", code: 1))
// before
observable
.catch { error in
.empty() // empty를 방출하면 onComplete도 방출
}
.subscribe()
.disposed(by: disposeBag)
// after
observable
.catchErrorJustComplete()
.subscribe()
.disposed(by: disposeBag)
}
- filterMap { }
private func filterMap() {
let observable = Observable.of(1,2,3,4,5,6)
// before
observable
.filter { $0 % 2 == 0 }
.map { $0 + 10 }
.subscribe()
.disposed(by: disposeBag)
// after
observable
.filterMap { $0 % 2 == 0 ? .map($0 + 10) : .ignore }
.subscribe()
.disposed(by: disposeBag)
}
- fromAsync
- closure 메소드를 observable로 표현하는 방법
- 인수는 Observable에서 받고, 클로저는 subscribe 블록에서 처리
private func fromAsync() {
func someAsynchronousService(arg1: String, arg2: Int, completionHandler: (String) -> Void) {
}
// 1. 함수 이름을 fromAsync안에 삽입
// 2. 파라미터는 뒤에 괄호로 추가
// 3. 함수의 클로저는 subscribe안에서 처리
Observable
.fromAsync(someAsynchronousService)("jake", 0)
.subscribe(onNext: { string in
print(string)
})
.disposed(by: disposeBag)
}
- partition
private func partition() {
let observable = Observable.of(1,2,3,4,5)
let (evens, odds) = observable.partition { $0 % 2 == 0}
evens
.subscribe()
.disposed(by: disposeBag)
odds
.subscribe()
.disposed(by: disposeBag)
}
* 전체 코드: https://github.com/JK0369/ExRxSwiftExt
* 참고
'iOS 응용 (swift)' 카테고리의 다른 글
Comments