일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- UICollectionView
- Refactoring
- tableView
- Observable
- SWIFT
- collectionview
- UITextView
- 리팩토링
- ribs
- HIG
- MVVM
- map
- rxswift
- RxCocoa
- Protocol
- ios
- 애니메이션
- Clean Code
- 클린 코드
- swiftUI
- 리펙터링
- swift documentation
- 리펙토링
- combine
- Xcode
- Human interface guide
- 스위프트
- clean architecture
- uitableview
- uiscrollview
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[RxSwift] 6.Filtering Operators 실습 본문
1. 구독을 공유해서 사용하는 방법 (Sharing subscriptions)
구독을 공유하는 주체 : Observable
1) 공유해서 사용하지 않은 경우의 문제점
여러 곳에서 subscribe()를 사용한다면 동기화에 문제 발생
<공유해서 사용할 함수와 변수 정의>
var start = 0
func getStartNumber() -> Int {
start += 1
return start
}
<Observable객체 생성>
let numbers = Observable<Int>.create { observer in
let start = self.getStartNumber()
observer.onNext(start)
observer.onNext(start+1)
observer.onNext(start+2)
observer.onCompleted()
return Disposables.create()
}
<subscribe>
numbers라는 Oservable객체가 heap영역에 할당된 변수(start)에 변형을 주는 함수에 두 번 접근하므로 값이 다르게 출력
numbers
.subscribe(
onNext: { el in
print(el)
},
onCompleted: {
print("Completed")
}
)
// print : 1, 2, 3, Completed
numbers
.subscribe(
onNext: { el in
print(el)
},
onCompleted: {
print("Completed")
}
)
// print : 2, 3, 4, Completed
※ 함수와 heap에 할당된 변수 그대로 유지하면서, subscribe시에 결과값을 변하지 않게 subscribe를 공유 하는 방법은?
share() 연산자 사용하는 것이 가장 좋은 방법
2) share() 연산자 없이 filter를 통해서 값을 걸러내는 방법
- Observable이 각각 생성됨
3) share() 연산자 사용
- share()를 사용하면, Observable하나로 처리 가능
(8. Transforming Operators in Practice에서 구체적으로 다룸)
2. Ignoring certain elements
(좌측 네비게이션 아이콘에 추가하는 함수)
//MainViewController.swift
private func updateNavigationIcon() {
let icon = imagePreview.image?
.scaled(CGSize(width: 22, height: 22))
.withRenderingMode(.alwaysOriginal)
navigationItem.leftBarButtonItem = UIBarButtonItem(image: icon,
style: .done, target: nil, action: nil)
}
// MainViewController.swift, viewDidLoad()
newPhotos
.ignoreElements()
.subscribe(onCompleted: { [weak self] in
self?.updateNavigationIcon()
})
.disposed(by: bag)
2) 세로보다 너비가 큰 이미지만 표시하도록 하기
filtert사용
newPhotos
.filter { newImage in
return newImage.size.width > newImage.size.height
}
[existing code .subscribe(...)]
3) 사진이 6개 이상 표시될 경우 "+"버튼 비활성화
newPhotos
.takeWhile { [weak self] image in
let count = self?.images.value.count ?? 0
return count < 6
}
[existing code: filter {...}]
3. 권한 설정 후 동작
권한설정을 하는 이벤트가 발생하면, 그 이후의 동작이 안되는 경우 존재
<해결방법>
권한 설정이 안되어 있다면, requestAccess(...)를 호출하는 코드 넣기
DispatchQueue.main.async {
if authorizationStatus() == .authorized {
observer.onNext(true)
observer.onCompleted()
} else {
observer.onNext(false)
requestAuthorization { newStatus in
observer.onNext(newStatus == .authorized)
observer.onCompleted()
}
}
}
<true일 경우만 이미지 업데이트 하기>
- skipWhile로 true만 오게끔 설정
- 한번만 업데이트 하면 되므로 take(1)로 설정
authorized
.skipWhile { $0 == false }
.take(1)
.subscribe(onNext: { [weak self] _ in
self?.photos = PhotosViewController.loadPhotos()
DispatchQueue.main.async {
self?.collectionView?.reloadData()
}
})
.disposed(by: bag)
cf) RxSwift에서는 GCD를 고려하지 않아도 됨 : Scheduling을 통해 해결(15장에서 계속)
4. 유저가 앨범 접근에 비동의 한 경우 처리
- 비동의 한 곳에 접근할 경우 error 메세지 출력
<이벤트 발생>
1) 무조건 이벤트가 2개이므로, skip(1), takeLast(1), distinctUntilChanged() 중 하나만 사용해도 됨
authorized
.skip(1) // 한 개의 이벤트를 skip
.takeLast(1) // 완료가 되면 1개 이전의 이벤트 발생
.distinctUntilChanged() // 중복값 방지
.filter { $0 == false } // false일 경우만 emit
.subscribe(onNext: { [weak self] _ in
guard let errorMessage = self?.errorMessage else { return }
DispatchQueue.main.async(execute: errorMessage)
})
.disposed(by: bag)
2) UIAlertController을 Rx스타일로 만들기
<alert 함수정의>
- 핵심은 present와 dismiss를 Rx적으로 모두 한 함수에 작성
func alert(title: String, text: String?) -> Completable {
return Completable.create { [weak self] completable in
let alertVC = UIAlertController(title: title, message: text, preferredStyle: .alert)
alertVC.addAction(UIAlertAction(title: "Close", style: .default, handler: {_ in
completable(.completed)
}))
self?.present(alertVC, animated: true, completion: nil)
return Disposables.create {
self?.dismiss(animated: true, completion: nil)
}
}
}
// cf) Completable : 이벤트 중, error와 completed만 emit하는 것
<alert함수 이용>
- 버튼을 클릭했을 때, 접근제한에 동의하지 않았으므로 메세지를 띄우고 -> "OK"버튼 -> alert dismiss -> popViewController
// PhotosViewController.swift
private func errorMessage() {
alert(title: "No access to Camera Roll",
text: "You can grant access to Combinestagram from the Settings app")
.subscribe(onCompleted: { [weak self] in
self?.dismiss(animated: true, completion: nil)
_ = self?.navigationController?.popViewController(animated: true)
})
.disposed(by: bag)
}
5. 시간에 기반한 filter 연산자
"time-based operators" == Scheduler
(11.Time Based Operators에서 계속)
- 구현 : 접근 제한 비동의한 곳에 접근하면 아래와 같이 경고문이 뜨는 상태,
이 상태에서 Close를 누르지 않아도 일정시간 종료하면 이전 화면으로 이동
<코드>
- .asObservable() 추가 : Completable to Observable (Completable은 take연산자를 사용하지 못하므로)
- .take(초, 스케줄러) 추가
alert(title: "No access to Camera Roll",
text: "You can grant access to Combinestagram from the Settings app")
.asObservable()
.take(5.0, scheduler: MainScheduler.instance)
.subscribe(onCompleted: { [weak self] in
self?.dismiss(animated: true, completion: nil)
_ = self?.navigationController?.popViewController(animated: true)
})
.disposed(by: bag)
'RxSwift > RxSwift 기본' 카테고리의 다른 글
[RxSwift] 8. Transforming Operators 실전(RESTful API) (0) | 2020.06.04 |
---|---|
[RxSwift] 7.Transforming Operators (0) | 2020.06.01 |
[RxSwift] 5.Filtering Operators (0) | 2020.05.26 |
[RxSwift] 4. Observables and Subjects 실전 적용 (0) | 2020.05.25 |
[RxSwift] 3. Subjects (0) | 2020.05.22 |