[TIL]RxSWIFT 4時間終了2


RxSWIFT四時間の平衡点2を参照


非同期でデータを受信する


完了方法

func downloadJson(_ url: String, _ completion: @escaping (String?) -> Void){
    // downloadJson이 끝나고 나중에 실행되는 함수라는걸 알려줄려고 escaping을 적어줌
    // ((String?) -> Void)? 이렇게 옵셔널인 경우 escaping이 default라 안적어줘도 됨
    DispatchQueue.global().async {
        let url = URL(string: url)!
        let data = try! Data(contentsOf: url)
        let json = String(data: data, encoding: .utf8)
        DispatchQueue.main.async {
            // ** 여기서 completion 사용
            completion(json)
        }
    }
}

@IBAction func onLoad() {
    downloadJson(MEMBER_LIST_URL){ json in // completion 구현
        self.editView.text = json
    }
}

受信した値を返す方法

class 나중에생기는데이터<T>{
    private let task: (@escaping (T) -> Void) -> Void
    
    init(task: @escaping (@escaping (T) -> Void) -> Void){
        self.task = task
    }
    
    func 나중에오면(_ f: @escaping (T) -> Void){
        task(f)
    }
}

func 다운로드받는함수(_ url: String) -> 나중에생기는데이터<String>{
    return 나중에생기는데이터() { f in // ** task
        DispatchQueue.global().async {
            let url = URL(string: url)!
            let data = try! Data(contentsOf: url)
            let json = String(data: data, encoding: .utf8)
            DispatchQueue.main.async {
                f(json)
            }
        }
    }
}

@IBAction func onLoad() {
    // ** 1. json에 나중에생기는데이터<String>을 담는다.
    let json: 나중에생기는데이터<String> = 다운로드받는함수(MEMBER_LIST_URL) 
    // ** 2. 나중에오면을 실행시켜 task를 실행시킨다.
    json.나중에오면{ json in // ** f
        self.editView.text = json
        self.setVisibleWithAnimation(self.activityIndicator, false)
    }
}
RxSwiftの観測性の基本原理を以下に示す.観測できないのは下に似ているのではないでしょうか…?
class Obsevalble<T>{
    private let task: (@escaping (T) -> Void) -> Void
    
    init(task: @escaping (@escaping (T) -> Void) -> Void){
        self.task = task
    }
    
    func subscribe(_ f: @escaping (T) -> Void){
        task(f)
    }
}

RxSWIFTの使用方法

func rx사용(_ url: String) -> Observable<String?>{
    return Observable.create{f in // ** 위에서의 task
        DispatchQueue.global().async {
            let url = URL(string: url)!
            let data = try! Data(contentsOf: url)
            let json = String(data: data, encoding: .utf8)
            DispatchQueue.main.async {
                f.onNext(json)
                f.onCompleted()
            }
        }
        // static func create(_ subscribe: @escaping (AnyObserver<String?>) -> Disposable) -> Observable<String?>
        // create안에 있는 클로져의 반환 값이 Disposable이기 때문에 Dispoable을 return 해준다.
        return Disposables.create() 
    }
}

rx사용(MEMBER_LIST_URL)
    .debug() // debug()를 통해 받아온 데이터, 생명 주기 확인 가능 
    .subscribe{ event in // ** 위에서의 f
        switch event{
        case .next(let json):
            self.editView.text = json
        case .error:
            break
        case .completed:
            break
        }
    }

ライフサイクルの観測

  • Create
  • Subscribe:サブスクリプションの時点から傍観者を実行します.
  • onNext
  • onCompleted or onError
  • Disposed
  • ✅⠀Subject

  • Subjectは傍観者であるため、1つ以上の観測可能なものを購読することができ、同時に1つのプロジェクトを通じて新しいプロジェクトを再配置、観察、排除することもできる.
  • で観測できるのはUnicast、SubcetはMulticast
  • 教室では観測不可能な値ではなくSubjectを使用します

    BehaviorSubejct



    傍観者がBehaviorSubjectの購読を開始すると、傍観者は、ソースの視覚的に最近発行されたアイテム(値が発行されていない場合は初期値またはデフォルト値)の発行を開始し、発行後にソースの視覚的に発行されたアイテムの発行を継続します.

    PublishSubject



    PublishSubjectは、購読後にソース観測可能アイテムを除外したアイテムのみを傍観者に送信します.
    PublishSubjectの欠点は、作成を阻止しない限り、すぐにプロジェクトの除外を開始し、これらの特性のため、トピックが作成された時間と傍観者がトピックの購読を開始した時間の間に、除外されたプロジェクトが失われる可能性があることです.この場合、PublishSubjectではなくReplaySubjectを使用する必要があります.

    ✅⠀Relay

  • Subjectはエラーが発生するとすぐにブレークしますが、Relayはエラーが発生してもブレークしません.
  • onNext()、onError()はaccept()として表すべきである.
  • スイッチ循環参照の管理

  • 弱使用
  • viewModel.totalPrice
        .map{ $0.currencyKR() }
        .observeOn(MainScheduler.instance)
        .subscribe(onNext: { [weak self] text in
            self?.totalPrice.text = text
        }).disposed(by: disposeBag)
  • DisposeBag
  • を使用
    override func viewWillDisappear(_ animated: Bool) {
        disposeBag = DisposeBag()
    }

    その他の関数

  • bind():subscribe()の使用が容易です.MainThreadで
  • を実行
    // subscribe 사용한 경우
    viewModel.totalPrice
        .map{ $0.currencyKR() }
        .observeOn(MainScheduler.instance)
        .subscribe(onNext: { 
            self.totalPrice.text = $0
        }).disposed(by: disposeBag)
    // bind 사용한 경우
    viewModel.totalPrice
        .map{ $0.currencyKR() }
        .bind(to: totalPrice.rx.text)
        .disposed(by: disposeBag)
  • take(n):n回のコールのみ.
  • _ = menuObservable
        .map{ menus in
            menus.map { m in
                Menu(id: m.id,name: m.name, price: m.price, count: 0)
            }
        }
        .take(1) // 한 번만 수행하기 계속 수행하면 스트림이 계속 생기기 때문
        .subscribe(onNext: {
            self.menuObservable.accept($0) 
        })
  • Dirver
  • // Driver 사용 전
    viewModel.itemsCount
        .map{"\($0)"}
        .observeOn(MainScheduler.instance) 
        .bind(to: itemCountLabel.rx.text)
        .disposed(by: disposeBag)
        
    // Driver 사용 후
    viewModel.itemsCount
        .map{"\($0)"}
        .asDriver(onErrorJustReturn: "") // error가 나면 .. ""로 리턴하겠다.
        .drive(itemCountLabel.rx.text)
        .disposed(by: disposeBag)
        
    // observeOn() 사용해서 메인쓰레드로 굳이 안바꿔줘도 됨

    今日


    昨シーズンに比べて基礎がしっかりしている.概念をより正確に把握できるので、より良い感じです.RxCocoaの実習も強化されていて、むくみすぎたので、ゆっくり理解して整理しなければなりません.🤯まだ難しいRx...しかし、久しぶりに新しいことを勉強して、とても面白いです.😊