Cancellable를 메모리에 남겨두자!

SteadySlower·2023년 4월 11일
0

Tips

목록 보기
11/19

Cancellable

Combine에서는 Publisher를 구독하는 경우 Cancellable을 리턴합니다. 이름에서 알 수 있듯이 Cancellable을 통해서 구독을 취소할 수 있습니다.

종종 이 Cancellable 객체를 메모리에 남겨두지 않는 실수를 하곤 하는데요. 그런 경우 어떤 일이 발생하는지 알아보겠습니다.

별 문제 없는 경우

아래의 publisher처럼 구독하자마자 모두 발행하고 complete하는 경우는 Cancellable를 메모리에 남겨두지 않아도 크게 문제 없습니다. 출력 결과에서 보듯이 함수 내에서 모든 발행과 completion을 끝내기 때문에 sink 다음에 있는 print("Subcribed!")가 발행물이 모두 출력된 이후에 출력되는 것을 볼 수 있습니다.

하지만 이런 경우는 실무에서는 거의 없습니다.

import Combine

let publisher = (1...10).publisher

func subscribe() {
    publisher
        .sink(receiveValue: { print($0) }) //👉 구독하는 순간 모두 발행
    print("Subcribed!")
}

subscribe()
// 🖨 출력 결과
1
2
3
4
5
6
7
8
9
10
Subcribed!

메모리에서 없어지면?

문제는 아래처럼 구독을 한 시점과 발행의 시점이 다른 경우입니다. 실무에서 흔하게 볼 수 있는 모습인데요. 아래 같은 경우 sink가 리턴하는 cancellable 객체는 subscribe의 함수가 실행되고 해당 scope를 벗어나면 메모리에서 사라집니다. 이렇게 되면 publisher가 발행해도 print 되지 않습니다.

import Combine

let publisher = PassthroughSubject<String, Never>()

func subscribe() {
    publisher
        .sink(receiveValue: { print($0) })
    print("Subcribed!")
}

subscribe()

// 발행
publisher.send("Hello world!")
// 🖨 출력 결과
Subcribed!

두 가지 방법

변수 이용하기

저장하는 방법 첫 번째는 변수를 이용해서 해당 변수에 할당하는 것입니다. 중간에 cancel할 가능성이 있서 특별하게 관리해야하는 구독에 사용하면 좋은 방법입니다.

import Combine

let publisher = PassthroughSubject<String, Never>()

var cancellable: AnyCancellable?

func subscribe() {
    cancellable = publisher
        .sink(receiveValue: { print($0) })
    print("Subcribed!")
}

subscribe()

publisher.send("Hello world!")
// 🖨 출력 결과
Subcribed!
Hello world!

배열 활용

중간에 취소할 필요가 크게 없는 경우, 구독이 많아서 하나하나 변수를 만드는 것이 불편한 경우 배열을 사용할 수 있습니다. .store를 사용해서 Cancellable의 배열에 넣어두면 됩니다.

import Combine

let publisher = PassthroughSubject<String, Never>()

var subscriptions = [AnyCancellable]()

func subscribe() {
    publisher
        .sink(receiveValue: { print($0) })
        .store(in: &subscriptions)
    print("Subcribed!")
}

subscribe()

publisher.send("Hello world!")
// 🖨 출력 결과
Subcribed!
Hello world!
profile
백과사전 보다 항해일지(혹은 표류일지)를 지향합니다.

0개의 댓글