아요 개발 일기

[RxSwift] Observable과 subscribe 본문

iOS/RxSwift

[RxSwift] Observable과 subscribe

소진이 2023. 1. 3. 15:39

안녕하세요 소진입니다 :)

이번에는 Observable과 subscribe에 대해 알아보겠습니당ㅎㅎ

 


 

🤔 Observable ?

Observable의 사전적 의미는 "관찰 가능한" 입니다.

해당 의미처럼 시간 흐름에 따라서 이벤트를 방출할 수 있는 동시에

구독자들이 그 이벤트를 관찰하는 역할을 합니다.

 

또한 Observable은 비동기적이라고하는데,

Observer에 의해 임의의 순서에 따라 병렬로 실행되고 결과는 나중에 연산되기 때문입니다.

 

즉, 하나의 코드 블럭이 실행 결과를 리턴할때까지 기다리지않고

계속해서 다음 코드 블럭을 실행하며

한번에 여러개의 코드를 실행 시키는 방식으로 진행됩니다.

 


 

Subscribe(구독)

Observable과 빼놓을 수 없는 짝꿍! subscribe은 무엇일까요?

 

Observable이 이벤트를 발생시키면 Observer의 관찰자가 그 순간을 감지하고 준비된 연산을 실행시켜 결과를 리턴하는데, 이를 Observable을 subscribe(구독)한다라고 합니다.

 

음.. 그러니까

Observable이 이벤트 방출하면

해당 Observable을 구독(subscribe)한 Observable이

방출한 이벤트를 가지고 액션을 취하는 것이겠군요?

 

 

어려우면 그림 참고하기!

 


이벤트 타입

 

Observable이 방출하는 이벤트는 아래와 같이 네가지 타입이 존재합니다.

 

✔️ OnNext

✔️ onError

✔️ onCompleted

✔️ onDisposed

 

Observable을 subscribe한 구독자는 위와같이 각 타입별로 이벤트를 전달받고

각 상황에 따라 액션을 취하게됩니다.

 


onNext

Observable에서 새로운 요소들을 방출할 때 마다 해당 메서드를 호출합니다.

파라미터 값: Observable이 방출하는 항목

 

onError

Observable이 기대한 값이 아니거나 오류가 발생한 경우 해당 메서드를 호출합니다.

파라미터 값: 오류 정보

(onNext, OnCompleted 호출 ❌)

 

onCompleted

Observable 시퀀스에서 에러가 발생하지 않고 더이상 방출할 요소가 없을 경우

onNext를 호출한 후 해당 메소드가 호출됩니다.

 

onDisposed

observable 시퀀스가 말 그대로 diaposed(버려진) 경우 onDisposed 이벤트가 호출됩니다.

이렇게 Observable이 각 상황에 따라서 이벤트를 골라 방출하게 됩니다.

 


 


 

subscribe(구독) 

 

저희가 Observable이 방출하게 될 1, 2, 3, 4에 대해 관심이 있다면

우선 뭘 해야할까요?

 

맞습니다!

바로 subscribe를 해야하죠?

subscribe를 해야 Observable이 어떠한 요소를 방출시키는지 알수있으니까요 :-)

 

subscribe하기 전에, 

아직 배우진 않았지만 of 연산자를 이용해서

1, 2, 3, 4를 방출해보도록 하겠습니다.

 

어렵지 않으니 편하게 따라해보세요!!

 

Observable.of(1, 2, 3, 4)는 시간 흐름에 따라서 1, 2, 3, 4를 방출하겠다는 의미를 가지고 있습니다!

 

let observable = Observable.of(1, 2, 3, 4)
observable.subscribe()

 

이렇게 1, 2, 3, 4를 순차적으로 방출하는 observable에 

.subscribe()만 해주면 구독이 됩니다.

 

구독만 해주면 아쉬우니,

위에서 배운 이벤트 처리도 해봅시다!

 

 

Observable을 구독하게되면 위 이미지처럼 자동 완성이되는데,

여기서 Element 있는 곳이 onNext에 해당하는 곳입니다.

 

그렇다는 것은!

Element의 의미가 Observable에서 방출하는 요소(1, 2, 3, 4)

라는 뜻이겠죠?

 

observable.subscribe { element in
    print("Observable로 부터 \(element) 를 전달 받았습니다.")
} onError: { error in
    print(error.localizedDescription)
} onCompleted: {
    print("Observable 이 정상적으로 종료 되었습니다.")
} onDisposed: {
    print("Observable 이 버려졌습니다.")
}

 

위처럼 코드를 작성하고

각 이벤트에 대한 처리를 해봅시다!

 

 

정상적으로 호출이 되었네요!

 

잠깐!

여기서 저희가 굳이 onDisposed 이벤트 처리는 하고 싶지 않다면

어떻게 해야할까요??

 

 

간단합니다 위 이미지 처럼 해당 클로저를 지우면 됩니다 ㅎㅎ

 

하지만

동시에 여러 이벤트가 생략되게 되면 

실행하고 싶지 않은 코드가 실행될 수도 있습니다.

 

 

예를들어,

onError와 onDisposed 이벤트가 생략되었다고 했을때

onError와 onDisposed이 아래 이미지의 초록색 박스 내에서 처리될 수도 있습니다.

 

그렇다면

해당 문제가 발생하지 않도록 해야겠죠?

 

위 이미지처럼 이벤트를 생략하여 subscribe할 때에는

onNext 같이 이벤트 타입을 꼭 명시해주면 해결됩니다!

 


 

⚠️ 메모리 누수 ⚠️

 

저희가 이벤트에 대한 처리를 클로저 내부에서 했었던거 기억하시나요?

 

클로저를 사용할때

메모리 누수를 방지하기위해 꼭 약한 참조를 사용해야했습니다!

 

그러면 이벤트에서도 사용해야겠죠??

observable.subscribe(onNext: { [weak self] _ in
		self?.someFunc()
})

 

위 코드와 같이 약한 참조를 사용해줍시다.

 

하지만

Rx에서 매번 [weak self]를 호출하는 것이 

번거로울 수 있다고 생각한 것인지

편리하게

이니셜라이저를 따로 만들어 주었습니다 : )

 

 

위 이미지처럼 with: 가 포함되어있는 .subscribe()를 사용하면 끝!

간단하죠?ㅎㅎ

 

 

with을 사용했을 때

observable.subscribe(with: self, onNext: { strongSelf, _ in
    strongSelf.someFunc()
})

이런식으로 with에 self를 넘겨주고 strongSelf로서 다시 받아주고서

strongSelf를 클로져 내부에서 자유롭게 사용하면 됩니다!

(strongSelf은 임의로 설정한 변수명)

 

with: 사용하지 않았을 때

observable.subscribe(onNext: { [weak self] _ in
    guard let strongSelf = self else { return }
    strongSelf.someFunc()
})

 

 

확실히 with를 사용하는게 코드가 훨씬 간결해보네요 ㅎㅎ

 

이번 글에서 연산자도 다루려고 했는데,

글이 생각보다 길어져서 다음 포스팅에서 다루도록 하겠습니다!


마치며..

Observable

✔️ 시간 흐름에 따라서 이벤트를 방출할 수 있는 동시에 구독자들이 그 이벤트를 관찰하는 역할

 

subscribe(구독)

✔️ 이벤트를 발생시키면 Observer의 관찰자가 그 순간을 감지하고 준비된 연산을 실행시켜 결과를 리턴하는 역할

✔️ 필요한 이벤트에 대해서만 골라서 처리할 수 있음

✔️ 각 이벤트 처리를 클로져에서 하므로 메모리 누수에 대해서 신경써야함