Refernce Post
김종권의 iOS 앱 개발 알아가기
Apple

(1) next: 구성 요소를 계속해서 방출시킬 수 있는 기능 (Observable 구독자에게 데이터 전달)
(2) completed: 이벤트를 종료시킬 수 있는 기능 (Observable 구독자에게 완료되었음을 알림)

(그림에서 끝에 막대기가 세로로 있는 것: 이미 일이 끝난 상태)
(3) error: 이벤트에 오류가 있음을 알고 중간에 종료시킬 수 있는 기능 (Observable 구독자에게 오류를 알림)

(이벤트에 오류를 포함하고 있는 경우 X로 표현)
(1) Observable.just(): 오직 하나의 요소를 포함하는 Sequence 생성
example(of: "just, of, from') {
// 1
let one = 1
let two = 2
let three = 3
// 2
let observable = Observable<Int>.just(one)
}
// exmaple method
public func example(of description: String, action: () -> Void) {
print("\n--- Example of: ", description, "---")
action()
}
(2) Observable.of(): 타입 추론을 이용하며 Sequence 생성
let observable2_1 = Observable.of(one, two, three)
let observable3_1 = Observable.of([one, two, three])
let observable3_2 = Observable.just([one, two, three])
☑️ [one, two, three]와 (one, two, three)의 차이를 주의하기~ (단일 요소인 배열, 배열이 아닌 다중 요소!)
(3) Observable.from(): 오직 array 타입만 처리하며 각각 요소들을 하나씩 emit 하는 기능
let observable4 = Observable.from([one, two, three])
(4) Observable.create(): 클로저 형식이며, 다양한 값(onNext, onCompleted 등)을 생성할 수 있음.
example(of: "create") {
let disposeBag = DisposeBag()
let observable = Observable<String>.create({ (observer) -> Disposable in
observer.onNext("1")
observer.onCompleted()
observer.onNext("?")
return Disposables.create()
})
observable.subscribe{ event in
print(event)
}
}
/* prints
next(1)
completed
*/
(5) Observable.empty()
(6) Observable.never()
(7) Observable.range(start: 1, count: 10)
(8) Observable.create()
옵저버에 대한 구독 즉, 옵저버에 담긴 이벤트들을 방출(emit) 하는 것이 subscribe 메소드를 사용하는 것
(1) observable.subscribe()
example(of: "subscribe") {
let one = 1
let two = 2
let three = 3
let observable = Observable.of(one, two, three)
}
observable.subscribe { event in
print(event)
/*
---- Example of : subscribe ----
next(1)
next(2)
next(3)
completed
*/
.subscribe는 정수의 이벤트 객체를 파라미터로 하는 escaping 클로저 형식 메소드로 반환값은 Disposable

(2) observable.subscribe(onNext:)
next 요소만 처리한다는 의미 (위에서 subscribe메소드는 completed까지 출력했지만 이것은 아닌 것을 확인)
observable.subscribe(onNext: { element in
print(element)
/* prints
1
2
3
*/
})
(3) empty()로 설정된 Oservable**
subscribe() 시, completed 만 출력
example(of: "empty") {
let oservable = Observable<Void>.empty()
observable.subscribe(
onNext: { element in
print(element)
},
onCompleted: {
print("Completed")
})
}
/* prints
Completed
*/
(4) never()로 설정된 Observable
subscribe() 시, completed 도 출력되지 않음
example(of: "never") {
let observable = Observable<Any>.never()
observable
.subscribe(
onNext: { element in
print(element)
},
onCompleted: {
print("Completed")
})
}
(5) range()로 설정된 Observable
클로저에서 인수를 주목 "(i) in"
example(of: "range") {
let observable = Observable<Int>.range(start:1, count: 10)
observable
.subscribe(onNext: { i in
let n = Double(i)
let fibonacci = Int(((pow(1.61803, n) - pow(0.61803, n)) / 2.23606).rounded())
print(fibonacci)
})
}
subscribe가 Observables 안에 있는 이벤트들을 방출(emit)하는 것이라면, Disposingdms subscribe를 취소하는 것 (구독 취소)
(1) dispose()
지금은 Observable의 이벤트가 3개 있어서 3개 출력 후 "completed"를 출력하지만, Observable의 이벤트가 무한 대기 등록되어 있다면 일정 수준에서 dispose()에서 종류 후 "comopletd" 출력
example(of: "dispose") {
let observable = Observable.of("A", "B", "C")
let subscription = observable.subscribe({ event in
print(event)
})
subscription.dispse()
}
(2) disposeBag
dipsose에 대한 리턴값을 담는 객체
example(of: "DisposeBag") {
let disposeBag = DisposeBag()
Observable.of("A", "B", "C")
.subscribe {
print($0)
}
.disposed(by: disposeBag) // subscrbie로부터 방출된 리턴 값을 disposeBag에 추가
print(disposeBag)
// prints: RxSwift.DisposeBag
}
93) Observable.create에서이 dispose
enum MyError: Error {
case anError
}
example(of: "create") {
let disposeBag = DisposeBag()
Observable<String>.create({ observer -> Disposable in
observer.onNext("1")
observer.onError(MyError.anError)
observer.onCompleted()
observer.onNext("?")
return Disposables.create()
})
.subscribe(
onNext: {print($0)},
onError: {print($0)},
onCompleted: {print("Completed")},
onDisposed: {print("Disposed")}
).dispose(by: disposeBaag) // 이 구문이 있는 이유: 메모리 제거함으로써 메모리 효율 확보
}
/* Prints:
1
anError
Disposed
*/
☑️ 코드의 흐름: 동기가 아닌 비동기이므로 주의! (create 블록과 subscribe 블록 동시에 실행이라고 생각)
(4) Observable.deferred()
example(of: defrred") {
let disposeBag = DisposeBag()
var flip = false
let factory: Observable<Int> = Observable.deferred() {
flip = !flip
if flip {
return Observable.of(1, 2, 3)
} else {
return Observable.of(4, 5, 6)
}
}
for _ in 0...3 {
factory.subscribe(onNext: {
print($0, terminator: "")
})
.disposed(by: disposeBag)
print()
}
}
Trait?
테스트 기능 또는 테스트 suite에 추가할 수 있는 특성을 설명하는 프로토콜
protocol Trait: Sendable
(1) Single: 성공이냐, 실패냐를 따지는 one-time 일에 적합 (파일 다운로드, 디스크로딩)
(2) Completable: Single과 기능이 유사하지만, value 값을 emit 하지 않음. 즉, 일이 제대로 됐는지만 검토할 때 사용 (파일 쓰기)
(3) Maybe: Single + Completable
ex) Single
example(of: "Single") {
let disposeBag = DisposeBag()
enum FileReadError: Error }
case fileNotFound, unreadable, encodingFailed
}
func loadText(from name: String) -> Single<String {
return Single.create { single in
let disposable = Disposables.create()
guard let path = Bundle.main.path(forResource: name, ofType: "txt") else {
single(.error(FileReadError.fileNotFount))
return dispoasable
}
guard let data = FileManager.default.contents(atPath: path) else {
single(.error(FileReadError.unreadable)
return disposable
}
guard let contents = String(data: data, encoding: .utf8) else {
single(.error(FileReadError.encodingFailed))
return disposable
}
single(.success(contents))
return disposable
}
}
// test
loadText(from: "myFile")
.subscribe {
switch $0 {
case .success(let string):
print(string)
case .error(let error):
print(error)
}
}
.disposed(by: disposeBag)
// prints: fileNotFound
}
(1) Observable.do
do 연산자는 Observable이 never든 뭐든 간에 일단 실행
example(of: "never") {
let observable = Observable<Any>.never()
let disposeBag = DisposeBag()
// 구독했음을 알리는 print("Subscribe")
observable.do(
onSubscribe: { print("Subscribe") }
).subscribe(
onNext: { element in
print(element)
},
onCompleted: {
print("Completed")
}).disposed(by: disposeBag)
}
// prints: Subsrcribe
(2) Observable.debug()
example(of: "never") {
let observable = Observable<Any>.never()
let disposeBag = DisposeBag()
observable
.debug("never 확인")
.subscribe()
.disposed(by: disposeBag)
/* prints
2024-10-28 17:07:03.123: never 확인 -> subscribed
2024-10-28 17:07:03.126: never 확인 -> isDisposed
*/
}