레이블이 RxSwift Basic인 게시물을 표시합니다. 모든 게시물 표시
레이블이 RxSwift Basic인 게시물을 표시합니다. 모든 게시물 표시

2018년 10월 25일 목요일

RxSwift의 기본 - Disposable

Disposable.

RxSwift에서 Disposable을 보면서 이것 참 C 스럽다는 생각이 많이 든다.
C언어를 해본사람들은 알겠지만 C에서 가장 귀찮은게 뭐냐고 물어본다면 포인터와 메모리 관리다.
이 배열의 첫 아이템이 배열의 주소니까 그걸 따라가서 복사한다음에 어쩌구 저쩌구...
그리고 그걸 자연스럽게 해제해주지 않으면 프로그램이 shut down!

사실 RxSwift에서도 동일한 작업이 이뤄진다.
이 시퀀스(Observable)이 저쪽에서 구독(subscribe)되고 또 그게 다른 변수로 복사된다음 합쳐지고 다시 이건 해제(Disposable)되는데 다른건 아직 안되서 결국은 메모리 누수가 발생한다.

제대로 해제해주지 않아 발생하는 에러...  RxSwift가 발전하면 언젠가는 이게 편하게 쓸수 있는 날이 올거라 믿는다.

아무튼, 이러한 이유로 어떻게 메모리 해제를 해야하는가에 대해 정리하고자 한다.
원래는 DisposeBag에 전부 넣어서 관리를 하려 했으나... 메인스케쥴러가 아닌 곳에서 시퀀스가 생성되고 돌아가다보니 뷰 컨트롤러가  Dismiss되어도 메모리에 찌꺼기처럼 계속 남는다.

ARC에서도 상호참조가 문제였는데 여기는 그 문제가 더욱 깊어진다.
좋다고 덮어놓고 쓰다보면 밤샘지옥이 기다리고 있을 것이다.

일단 RsSwift에서 사용하는 Disposable의 종류를 알파벳순으로 정리해보면 다음과 같다.

AnonymousDisposable
 - action base의 Disposable
 - Dispose 된 이후 실행시킬 Action을 지정할 수 있다.

BinaryDisposable
 - 동시에 Dispose될 2개의 Disposable을 지정한다.

BooleanDisposable
 - dispose되었는지에 대한 스테이터스를 확일 할 수 있는 Disposable

CompositeDisposable
 - 여러개의 disposable을 하나로 묶을 수 있는 Disposable

NopDisposable
 - Nop: No operation
 - Dispose를 해도 Dispose하지 않고 아무것도 하지 않는다.

RefCountDisposable
 - ARC(Auto Reference Counting)를 해주는 Disposable

ScheduledDisposable
 - 지정한 스케쥴러에 의해 Dispose처리를 함

SerialDisposable
 - 새로운 Disposable을 넣으면 기존에 있던 Disposable이 Dispose됨. -> 병렬처리

SingleAssignmentDisposable
 - 1개만을 집어 넣을 수 있는 Disposable
 - 2번째를 넣으면 Exception을 발생시킨다

DisposeBag
 - 자기 자신이 메모리에서 해제될때 같이 Dispose되는 Disposable


** Disposable은 프로토콜 타입이다. 따라서 Disposable만을 생성하는 것은 불가능하다.

2018년 10월 23일 화요일

RxSwift의 기본 - RxCocoa - 작성중

UIKit에 맞춰 편리하게 만들어 놓은 라이브러리.
Driver 라던가 control event 등이 추가되어 있음.

RxSwift의 기본 - RxSwift의 3대 기둥(Observable, Operator, Scheduler) - 작성중

RxSwift는 아래와 같은 3개의 기둥이 있다.

- Observable

- Operator

- Scheduler


Observable

- Observable은 시퀀스의 타입이다.
- 스트림과 비슷한 개념이지만 시퀀스라고 이름이 붙어 있다.
- 뜻 그대로 옵저버 패턴에 있어서 옵저버가 가능한 시퀀스를 만들어내는 타입이다.

이 시퀀스에는 크게 3가지의 이벤트가 있다.
 - onNext: 시퀀스에 아이템을 흘려보낸다.
 - onError: 시퀀스에 에러가 발생했으므로 에러를 넘기고 종료한다.
 - onComplete: 시퀀스를 종료한다.

하나의 시퀀스가 종료되면 다시 생성하기 전까지 아이템이 흘러가지 않는다.


Observable(시퀀스)를 선언하고 subscribe(구독)을 하므로 rxSwift를 사용하게 된다. 그리고 마지막에 dispose(처리)하므로 시퀀스가 메모리에서 삭제된다.

간단한 예를들어보면
1
2
3
4
Observable<Int>.just(1)
    .subscribe { event in
        print(event)
    }.dispose()
cs

위와 같은 코드가 있다고 할때 .just(1)이 observable을 생성하는 operator가 된다. 그리고 1을 만드는 시퀀스를 구독하여 print하고 그대로 dispose()하고 있는 간단 심플한 코드이다.



Operator

rxSwift를 쓰는 이유는 하나의 이벤트를 기준으로 여러가지 기능을 하기 위해서다. 따라서 여러가지 이벤트를 하나의 이벤트로 합치거나, 시간을 조절하여 이벤트를 받거나 발생시킬 필요가 있다. 그 때 쓰는 것이 Operator이다.
그리고 이 operator가 함수형 프로그래밍의 꽃이 된다.
예를들면, map(), merge(), zip(), concat() 등이 대표적인 Operator이다.
map, filter, reduce는 일반적인 배열에서의 사용법과 같다.


Scheduler
시퀀스의 이벤트를 어떤 큐에서 어떤 타이밍에 발생시킬가에 대한 문제.

RxSwift의 기본 - 서문

리엑티브 익스텐션(Reactive eXtension, 이하 리엑티브) 프로그래밍을 한지 어언 1년이 다되어감에도 불구하고 여전히 개념이 확실히 잡혀있지 않다.

기본적인 observable과 driver, 그리고 map, distinct같은 연산자만 쓰다보니 실력이 늘지를 않는다.

역시 이게 문제였는지 에러가 발생한다.

한 유저가 1초에 30건씩 request를 보내고 있는 것이다.

1초에 30건씩 한 유저니 동시접속 100유저면 3천건 1분에 18만건 10분에 180만건 한시간에 1억건이 넘는 리퀘스트를 처리해야 하니 서버가 뻗어버린다.

다행히도 인프라팀에서 이걸 일찍 발견하여 그 리퀘스트를 날리는 부분을 막는 핫픽스를 업데이트 하고 트래픽도 늘렸기에 별문제는 없었다.

그렇게 한숨돌리고 원인을 찾아보니.

rxswift에서 중요한 개념인 hot/cold의 개념이 역시나 발목을 잡았다.

물론 저걸 몰라도 풀수 있는 문제였다.

핵심적인 문제는 rxSwift에서 dispose를 할때 어플 전반적으로 DisposeBag을 활용했는데 이게 viewmodel이 상호참조가 되어버려 인스턴스가 종료되지 않아 결국 DisposeBag도 dispose되지 않은채 영영 살아있고 Observable.Interval()을 사용하고 있었기에 설정 한 시간만큼 기하급수로 리퀘스트가 늘어나고 있었다.


따라서 이 기회에 hot과 cold의 개념을 포함한 rxSwift의 기본기를 좀더 확실하게 다지고자 포스트를 써 본다.