associatedtype (연관타입)으로 지정함으로써 순회해서 가져온 요소의 타입을 지정할 수 있음!
next() 메소드는 시퀀스에 있는 다음 요소를 반환하거나, 시퀀스의 마지막인 경우 nil 을 반환함!
public protocol IteratorProtocol {
associatedtype Element
public mutating func next() -> Self.Element?
}
Sequence Protocol
Sequence Protocol을 채택해야만 for…in 순환문으로 반복 순회가 가능함
Iterator Protocol을 채택해야함!
makeIterator() 메소드는 직접 호출할 필요는 없으며 스위프트 런타임시 for...in 순환문을 사용할 때 자동으로 호출됨
RxSwift에서 Sequence는 반복하고 있는 작업을 말함
public protocol Sequence {
associatedtype Iterator: IteratorProtocol
public func makeIterator() -> Self.Iterator
}
for a in array {
// 해당 반복문을 가능하도록 하는 프로토콜이 Sequence 이다!
}
RXSwift
AlamoFire와 같은 라이브러리(tool)일 뿐임!
서드파티앱
코드를 외워서 짜는 것이 아니고 다양한 예제들을 보면서 학습 해보면 됨!
operator가 엄청 많음!(고차함수와 같은 것)
operator에 빠지지 말고 만들어진 메서드에 불과하다는 것을 생각하고 사용하면 됨!
디버깅이 어려움!
Observable
계속 이벤트를 전달함!
Obsever가 없다면 아무 처리를 할 수 없음!
나중에 Observer가 생긴다면 생성 이후부터 처리가능함!
subscribe를 할 수 없음
LifeCycle
Create 연산자를 통해 Observable을 생성함 (보통 구현되어 있는 Operator를 사용함)
Subscribe가 되면 Observable이 실행됨
next를 통해 이벤트(제스쳐, 인스턴스 등)을 Emit함
Lifecycle 중 오류가 발생한다면 error 이벤트를, 정상적으로 모든 이벤트가 완료된다면 completed를 Notification함
deinit 되는 시점, Sequence가 종료되는 시점에 Dispose가 됨
error 또는 completed를 전달받으면 Sequence가 종료되고 종료된 이후에는 더 이상 이벤트가 발생하지 않음 즉, Observable에 대한 재사용이 불가능함
Emit: Next(여러번 발생 가능) - 점진적 다운로드, 최신 데이터 전달 → Append Buffer
Notification: Error(지속적 방출 옵션X) - 디코딩 실패, 상태 코드 오류, 네트워크 연결 유실 → Alert(기능적인 부분에서만 발생)
Finite observable sequences
유한한 시퀀스가 사용되는 곳은 예를 들면 끝이 나면 자연스럽게 종료되어야 하는 동작인 다운로드와 같은 것을 말함!
ex) iOS 앱에서 인터넷에서 파일을 다운로드하는 상황
다운로드를 시작하고 들어오는 데이터를 관찰하기 시작합니다.
그런 다음 파일의 일부가 도착할 때 data 의 chunk 를 반복적으로 수신합니다.
네트워크 연결이 끊어지면 다운로드가 중지되고 연결 시간이 초과되어 오류가 발생합니다.
또는, 파일의 모든 데이터를 다운로드하게 되면 성공적으로 완료됩니다.
API.download(file: "<http://www>...")
.subscribe(
onNext: { data in
},
onError: { error in
},
onCompleted: {
}
)
Infinite observable sequences
위에서 본 자연스럽게 종료되어야 하는 다운로드와 달리 무한한 시퀀스가 있음
기본적으로 UI 이벤트와 같은 것들은 무한한 시퀀스임
ex) 앱이 기기가 세로인지 가로인지에 대해서 대응하는 코드를 생각해봤을때
NotificationCenter로부터 UIDeviceOrientationDidChanged 알림에 대한 observer 로 클래스를 추가할 수 있음!
그런 다음 방향 변경을 처리하기 위해 method callback 을 제공해야 합니다. UIDevice 에서 현재 방향을 가져와서 최신 값에 따라 반응해야 합니다.
그럼 아래와 같이 방향 전환이 되었을 때인 subscribe 상태에서 switch나 if문과 같이 조건문을 활용해서 분기처리를 해볼 수 있음
UIDevice.rx.orientation
.subscribe(onNext: { current in
switch current {
case .landscape:
// Re-arrange UI for landscape
case .portrait:
// Re-arrange UI for portrait
}
})
이러한 방향 변경 시퀀스에는 끝이 없고 시퀀스는 거의 무한대이고 상태를 저장하므로 관찰을 시작할 때 항상 초기 값이 있음
사용자가 기기를 절대로 회전하지 않는 경우도 있지만 그렇다고 이벤트의 시퀀스가 종료되는 것은 아니고 이벤트가 발생하지 않는 것을 의미함
Scheduler
스케쥴러는 작업을 어디서 수행할지에 관한 작업을 추상화함
Main thread에서 수행할지, background에서 수행할지 등을 정할 수 있게 해줌
RxSwift에서는 스케줄러를 통해 Observable을 생성하는 작업을 어디서 할지 그리고 Observer가 시퀀스를 관찰하는 작업을 어디서 할지 정할 수 있음
Observer
이벤트에 대해서 계속 관찰하고 있어야함!
이벤트가 발생하면 아래와 같이 이벤트에 대한 처리를 함!
특정 액션에 대해 실행을 시켜주는 트리거의 역할을 함!
Subscribe - 구독하면 그때부터 Observer가 이벤트에 대해서 관찰하며 아래와 같이 구동하고 있는 대상의 다음 값, 에러가 났을 경우, 완료된 경우에 대한 시점에 대한 분기처리가 가능함
Observable.just(itemsA)
.subscribe { value in
print("just - \\(value)")
} onError: { error in
print("just - \\(error)")
} onCompleted: {
print("just completed")
} onDisposed: {
print("just disposed")
}
.disposed(by: disposeBag)
Dispose - 어떤 조건을 만족했을 경우 Dispose를 주면 구독 취소 가능
Bind - subscribe에서 onNext 매개변수만 가져와서 사용하기 때문에 error 이벤트를 받지 않는 다는 특성이 있음! 그러므로 UI 부분을 처리해줄때 적합함!
//Of: observable의 object들을 모두 Emit함(여러개의 object 담기 가능)
func exmpleOf() {
Observable.of("💩","👻","👾","🤖","🤡")
.subscribe { element in
print(element)
}
.disposed(by: disposeBag)
}
from - 배열의 element의 요소들의 개수만큼 방출함
//from: 배열만 받을 수 있고 배열의 원소의 개수마다 emit함
func exampleFrom() {
Observable.from([1,2,3,4,5])
.subscribe { value in
print(value)
}
.disposed(by: disposeBag)
}
repeatElement - 계속 방출함
.take(Int) - repeat에 대해서 몇 번 방출할지를 제한 가능
//repeatElement: .take(i) i번 만큼 observable로 방출된 요소를 출력함
func exmpleRepeatElement() {
Observable.repeatElement("🔴")
.take(3)
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
}
range - start부터 count 크기 만큼의 observable로 각각 방출된 요소에 대해서 값을 Double로 변환 후 출력함
//range: start부터 count 크기 만큼의 observable로 각각 방출된 요소에 대해서 값을 Double로 변환 후 출력함
func exampleRange() {
Observable.range(start: 1, count: 10)
.subscribe { value in
print(Double(value))
}
.disposed(by: disposeBag)
}
interval(.seconds(Int)) - 정해진 시간마다 계속 방출함
create - 커스텀한 observable 시퀀스를 생성해주며 하나의 element만 담을 수 있고 한번만 emit한 후에 출력함
//create: 커스텀한 observable 시퀀스를 생성해주며 하나의 element만 담을 수 있고 한번만 emit한 후에 출력함
func exampleCreate() {
let myJust = { (element: String) -> Observable<String> in
return Observable.create { observer in
observer.on(.next(element))
observer.on(.completed)
return Disposables.create()
}
}
myJust("🔴")
.subscribe { print($0) }
.disposed(by: disposeBag)
}
combineLatest - 여러 개의 element를 등록 가능하고 등록된 개체 중 하나만 변경되어도 실행됨
.orEmpty - 옵셔널 값 벗겨줌
.tap - touchUpInside와 같음
generate - initialState - 초기값 설정, condition - 조건 부여, iterate - 시퀀스마다 어떻게 반복할지 이렇게 앞에 지정해준 초기값, 마지막 값에 대한 조건, 반복조건에 대한 observable을 emit 후 출력함