Observable | Subject |
---|---|
함수, state X | state O, data를 메모리에 저장 |
각각의 옵저버에 대해 코드가 실행 | 같은 코드 실행, 모든 옵저버에 대해 오직 한번만 |
Data Producer | Date Producer and Consumer |
용도 : 간단한 하나의 옵저버가 필요할 때 | 용도 : 데이터가 자주 바뀔때, 옵저버와 옵저버 사이의 Proxy 역할 |
추가적으로 Subject는 ObserverType를 따르고 있어 바로 on 함수를 구현 가능하기에 Observable, Observer들 간의 interaction, 유연성있는 코드도 가능할 것이다.
가장 중요한 것은 외부데이터를 가져와서 통로 넣어줄 수 있다는 점!
// MARK: - PublishSubject
let psubject = PublishSubject<String>() //비어있는 상태
psubject.onNext("First")
psubject.subscribe{ event in
print(event)
}
psubject.onNext("Second")
psubject.onNext("Third")
//next(Second)
//next(Third)
//completed
let bsubject = BehaviorSubject(value: "Initial value")
bsubject.onNext("Second Value")
bsubject.subscribe { event in
print(event)
}
bsubject.onNext("Last value")
let rsubject = ReplaySubject<String>.create(bufferSize : 3) //버퍼사이즈를 바꾼다면?
rsubject.onNext("First")
rsubject.onNext("Second")
rsubject.onNext("Third")
rsubject.subscribe { event in
print(event)
}//.dispose()를 넣는다면?
rsubject.onNext("Fourth")
let asubject = AsyncSubject<Int>()
asubject.onNext(1)
asubject.onNext(2)
asubject.onNext(3)
asubject.onCompleted()
aSubject.subscribe({event in
print(event)
})
asubject.onNext(4)
asubject.onNext(5)
func getRepo(_ repo: String) -> Single<[String: Any]> {
return Single<[String: Any]>.create { single in
let task = URLSession.shared.dataTask(with: URL(string: "https://api.github.com/repos/\(repo)")!) { data, _, error in
if let error = error {
single(.error(error))
return
}
guard let data = data,
let json = try? JSONSerialization.jsonObject(with: data, options: .mutableLeaves),
let result = json as? [String: Any] else {
single(.error(DataError.cantParseJSON))
return
}
single(.success(result))
}
task.resume()
return Disposables.create { task.cancel() }
}
}
// Alamofire 라이브러리 사용 예제
extension NetworkManager {
func request<T: BaseResponseModelable>(_ url: Alamofire.URLConvertible, method: Alamofire.HTTPMethod, parameters: Alamofire.Parameters?, headers: Alamofire.HTTPHeaders?) -> Single<T> {
return Single<T>.create { (single) -> Disposable in
let request = self.sendRequest(url, method: method, parameters: parameters, headers: headers, handler: { (result: Result<T>) in
switch result {
case .success(let value):
single(.success(value))
case .failure(let error):
single(.error(error))
}
})
return Disposables.create {
request.cancel()
}
}
}
}
Traits는 observable sequence에 대한 빌더 패턴 구현의 일종.
Trait가 만들어지면, asObservable()을 호출하면 그것을 흔한 Observable sequence로 다시 변환
.success(value) 는 .next + .completed
Observable -> Single, Maybe 변환 가능 Completable 불가능
func completable() -> Completable {
return Completable.create { completable in
// Store some data locally
guard success else {
completable(.error(CacheError.failedCaching))
return Disposables.create {}
}
completable(.completed)
return Disposables.create {}
}
}
completable().subscribe(
onCompleted: { print("Completed with no error")
},
onError: { error in print("Completed with an error: \(error.localizedDescription)")
}
).disposed(by: disposeBag)
//사용법
getRepo("ReactiveX/RxSwift")
.subscribe { event in
switch event {
case .success(let json):
print("JSON: ", json)
case .error(let error):
print("Error: ", error)
}
}
.disposed(by: disposeBag)
func maybe() -> Maybe<String> {
return Maybe<String>.create { maybe in
maybe(.success("RxSwift"))
// or
maybe(.completed)
// or
maybe(.error(error))
return Disposables.create {}
}
}
maybe().subscribe(
onSuccess: {
element in print("Completed with element \(element)")
},
onError: { error in print("Completed with an error \(error.localizedDescription)")
},
onCompleted: { print("Completed with no element")
} ).disposed(by: disposeBag