[iOS] RxSwift 입문

someng·2023년 5월 4일
0

iOS

목록 보기
31/33

❓ RxSwift의 등장 배경

비동기 작업의 결과물을 @escaping completion으로 콜백 하지 않고, 리턴 값으로 전달해줄 수는 없을까?

🐥 등장한 아이들

  • PromiseKit
  • Bolt
  • RxSwift

  • 나중에 생기는 데이터 (Observable)
  • 나중에 오면 (subscribe)

RxSwift

event의 종류 (enum)

  • .next
  • .completed
  • .error

순환 참조 막는 방법

: onNext() 호출 이후에 onCompleted() 호출
→ 클로저 사라지면서 Reference Counting 감소

  • disposable : subscribe의 리턴값. 동작이 끝나지 않았을 때도 작업을 취소할 수 있음.

🥏 Observable의 생명 주기

  1. Create
  2. Subscribe (이 때, Create된 로직 실행됨)
  3. onNext
    ---- 끝 ----
  4. onCompleted / onError ⇒ 끝나는 조건 2가지
  5. Disposed

🧚‍♀️ Sugar API

: RxSwift 코드를 간단하게 만들어주는 Operator

- 데이터 하나 보낼 때 (Just)

return Observable.just("Hello World")

코드 3줄을 한줄로 만들어줌 👍🏻

return Observable.create { emitter in
	emitter.onNext("Hello World")
    emitter.onCompleted()
    return Disposables.create()
}

- 데이터 여러개 차례로 보낼 때 (From)

return Observable.from(["Hello", "World"])

- 실행할 thread 지정 (observeOn)

downloadJson(MEMBER_LIST_URL)
	.observeOn(MainScheduler.instance)
    .subscribe(onNext: { json in
    	self.editView.text = json
		...
    })

아래와 동일한 효과

downloadJson(MEMBER_LIST_URL)
    .subscribe(onNext: { json in
    	DispatchQueue.main.async {
          self.editView.text = json
          ...
        }
    })

- subscribe하는 시점의 thread 지정 (subscribeOn)

- Merge: 여러 Observable(같은 타입) 을 하나로 합쳐준다

- Zip: 데이터를 쌍으로 보내준다 (타입 달라도 무관)

let jsonObservable = downloadJson(MEMBER_LIST_URL)
let helloObservable = Observable.just("Hello World")

_ = Observable.zip(jsonObservable, helloOberservable) { $1 + "\n" + $0 }
	 .subscribe(onNext: { json in
    	self.editView.text = json
		...
    })
    
// 실행결과: 
Hello World
[json 파일]

- CombineLatest: 가장 최근의 데이터를 쌍으로 보내준다

- bind (RxCocoa import 필요)

viewModel.itemsCount
	.map { "\($0)" }
    .observeOn(MainScheduler.instance)
    .bind(to: itemCountLabel.rx.text)
    .disposed(by: disposeBag)

코드 3줄을 1줄로 만들어줌 👍🏻
+) weak self 없이 순환 참조 방지 가능

viewModel.itemsCount
	.map { "\($0)" }
    .observeOn(MainScheduler.instance)
    .subscirbe(onNext: { [weak self] in
    	self?.itemCountLabel.text = $0
    })
    .disposed(by: disposeBag)

✅ Table View에 bind
→ TableView DataSource 필요 없어짐!

viewModel.menuObservable
	.observeOn(MainScheduler.instance)
	.bind(to: tableView.rx.items(cellIdentifier: cellId, cellType: MenuItemTableViewCell.self)) { index, item, cell in 
    cell.title.text = item.name
    cell.price.text = "\(item.price)"
    cell.count.text = "\(item.count)"
}
	.disposed(by: disposeBag)

- Driver
: UI용 Observable
RxCocoa를 사용해서 UI bind를 할 때

1) main thread 에서 실행
2) 에러가 발생할 때 리턴할 값 지정

두 가지가 항상 필요한데 driver가 이 작업을 간단하게 만들어준다.

// driver 사용 X
viewModel.itemsCount
	.catchErrorJustReturn("")
    .observeOn(MainScheduler.instance)
    .bind(to: itemCountLabel.rx.text)
    .disposed(by: disposeBag)
    
// driver 사용 O
viewModel.itemsCount
	.asDriver(onErrorJustReturn: "")
    .drive(itemCountLabel.rx.text)
    .disposed(by: disposeBag)

- Relay
: UI용 Subject (연결이 끊어지지 않음)

  • 종류는 Subject와 동일
  • complete/error 발생하지 않고 오로지 accept(=next)

이외 Operator

🍄 DisposeBag

  • subscribe의 리턴값인 Disposable 여러개를 하나에 담는 역할.
  • deinit할 때, 배열에 추가되어있는 disposable들을 dispose 한다!

RxCocoa

RxSwift 기능을 UIKitExtension으로 추가한 것

🍄 Subject

: Observable 처럼 값을 구독할 수 있고, Observable 외부에서 데이터를 주입할 수 있다

  • PublishSubject

    : Subject에 누군가 subscribe할 수 있음

  • BehaviorSubject

    : 기본값을 발행한 후, 새로운 데이터가 발생할 때 발행함

  • AsyncSubject

    : complete 되는 시점에 가장 마지막 데이터를 모든 구독자에게 발행함

  • ReplaySubject

    : 이때까지 발행된 모든 데이터를 발행 받고 이후에는 PublishSubject와 같이 값을 받음

profile
👩🏻‍💻 iOS Developer

0개의 댓글