세상을 더 편리하게
article thumbnail
728x90

AnyCancellable

import Combine
import SwiftUI

struct CombineView: View {
    
    var vm = CombineViewModel()
    @State var anyCancellable = Set<AnyCancellable>()
    @State var number = 0
    
    var body: some View {
        VStack {
            Text("\(number)")
                .padding()
            
            Button(action: { vm.number.send(Int.random(in: 1...1000))  // # 수정됨
//                print(vm.number)
            }, label: {
                Text("Button")
            })
            
            Button(action: {
                anyCancellable.first?.cancel()
            }) {
                Text("Cancel")
            }
            .padding()
            .onAppear {
                vm.number.sink { [self] value in
                    DispatchQueue.main.async {
                        self.number = value
                    }
                }.store(in: &anyCancellable)
            }
            
        }
    }
}

class CombineViewModel {
    var number = PassthroughSubject<Int, Never>()
}

Cancel을 누르는 순간 숫자가 변하지 않는 것을 볼 수 있을 것이다.

즉, AnyCancellable의 cancel 함수를 작동시키면 Publisher와 Subscriber의 관계를 끊는 것이다.

그럼 왜 끊는 것이 필요할까?

필요 없이 Subscriber를 작동하는 것은 큰 오버헤드를 가져오기 때문이다.

오버헤드(overhead): 어떤 처리를 하기 위해 들어가는 간접적인 처리 시간 · 메모리 등을 말한다.

자동으로 끊어 질까?

Publisher - Subscriber의 연결되어 있는 것은 큰 오버헤드가 발생한다. 

코딩하다가 문뜩 생각이 들었다. 사실 Publisher-Subscriber는 사용자가 끊어주지 않으면 계속 연결되어 있는건가?

아니면 메모리에 사라지면 알아서 연결이 끊어지는 걸까?

오 다행히 마지막 줄을 보면 AnyCancellable은 메모리에서 해제될 때 자동으로 cancel을 호출한다고 적혀 있다.

그럼 화면이 사라짐과 동시에 메모리에서 해제됨으로 Publisher와 Subscriber의 관계를 끊어버리니 메모리와 오버헤드를 고려 안해도 될 것 같다!

하.지.만

다시 생각해보자. sink 함수의 반환 값은 AnyCancellable이다. 그리고 AnyCancellable은 Class 이다.

만약 값을 저장하지 않으면 생성과 동시에 메모리에서 사라진다.

즉 Publisher - Subscriber의 관계를 유지할 수 없다는 것이다.

그러니 Publisher - Subscriber의 관계를 유지 하고 싶다면 반드시 AnyCancellable을 변수에 저장하던가.

store 함수를 이용해 Set<AnyCancellable> 에 저장해야 할 것이다.

728x90
profile

세상을 더 편리하게

@쵱니

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!