ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Combine - 연산자 receive/sink/store
    Swift 2024. 2. 21. 21:49

    viewModel.selectedItem
                .compactMap { $0 }
                .receive(on: RunLoop.main)
                .sink { framework in
                    let sb = UIStoryboard(name: "Detail", bundle: nil)
                    let vc = sb.instantiateViewController(withIdentifier: "FrameworkDetailViewController") as! FrameworkDetailViewController
                    vc.viewModel = FrameworkDetailViewModel(framework: framework)
                    self.present(vc, animated: true)
                }.store(in: &subscriptions)

    해당 코드는 Combine 프레임워크를 사용하여 데이터 흐름을 처리하는 방식을 보여주는 예시입니다. 코드를 각 부분별로 설명하겠습니다:

    1. `viewModel.selectedItem`: `viewModel` 객체의 `selectedItem` 속성을 나타냅니다. 이 속성은 Combine의 `CurrentValueSubject`나 `PassthroughSubject`와 같은 Publisher 타입입니다.

    2. `.compactMap { $0 }`: `selectedItem`의 값을 optional에서 non-optional로 변환하기 위해 `compactMap` 연산자를 사용합니다. optional 값을 unwrapping하고, non-optional 값만을 포함하는 스트림을 생성합니다.

    3. `.receive(on: RunLoop.main)`: 데이터 스트림을 메인 스레드에서 처리하도록 지정합니다. UI 업데이트와 관련된 작업은 일반적으로 메인 스레드에서 수행되어야 하므로, `receive(on:)` 연산자를 사용하여 메인 스레드에서 처리하도록 설정합니다.

    4. `.sink { framework in ... }`: 데이터 스트림의 값을 받아 처리하는 부분입니다. `sink` 연산자를 사용하여 데이터 스트림의 값을 받아옵니다. 클로저에서는 받아온 `framework` 값을 사용하여 `FrameworkDetailViewModel`을 생성하고, 해당 뷰 모델을 이용하여 `FrameworkDetailViewController`를 생성하고 표시합니다.

     

    ⭐️실제로 데이터를 처리하는 부분
    위 코드에서는 viewController를 생성(FrameworkDetailViewModel)하고, 데이터를 넣어준다. 

     


    5. `.store(in: &subscriptions)`: `sink` 연산자에서 반환된 `AnyCancellable`을 `subscriptions` 변수에 저장합니다. `AnyCancellable`은 데이터 스트림의 구독을 취소할 수 있는 기능을 제공합니다. 해당 구독을 취소하려면 `subscriptions` 변수에 저장된 `AnyCancellable` 객체를 해제해야 합니다.


    .store(in: &subscriptions)부분이 없으면?
    이 코드는 Combine을 사용하여 데이터 흐름을 처리하고, `selectedItem`의 값이 변경되면 해당 값을 처리하는 방식을 보여줍니다. `selectedItem`의 값이 변경되면 메인 스레드에서 `FrameworkDetailViewController`를 생성하고 표시하는 동작이 수행됩니다.

    .store(in: &subscriptions) 부분이 없다면, 구독이 AnyCancellable 객체에 저장되지 않고 따로 참조되지 않게 됩니다.

    이 경우, 구독이 유지되는 동안 AnyCancellable 객체가 존재하지 않기 때문에 구독을 취소하거나 해제할 수 있는 참조가 없게 됩니다. 따라서, 해당 구독을 취소하거나 해제할 수 있는 방법이 제한되며, 메모리 누수가 발생할 수 있습니다.

    따라서, AnyCancellable 객체를 적절히 저장하는 것은 구독의 수명 주기를 관리하고 메모리 누수를 방지하기 위해 중요합니다. .store(in: &subscriptions)를 통해 AnyCancellable 객체를 subscriptions 변수에 저장함으로써, 필요한 시점에 구독을 취소하고 메모리를 해제할 수 있게 됩니다.

     

     

    .store(in: &subscriptions) 외에도 구독을 관리하고 해제하는 다른 방법들이 있습니다.

    1. 수동으로 구독 취소: AnyCancellable 객체를 직접 해제하는 방법입니다. 구독을 취소하기 위해 cancel() 메서드를 호출하면 됩니다. 예를 들어, 구독을 취소하고 AnyCancellable 객체를 해제하려면 다음과 같이 할 수 있습니다:

    let cancellable = somePublisher.sink { value in
        // 처리 로직
    }
    
    // 구독 취소
    cancellable.cancel()

     

    Assign 연산자 사용: @Published 속성이나 ObservableObject를 사용하는 경우, assign(to:on:) 메서드를 사용하여 구독을 생성하고 속성에 값을 할당할 수 있습니다. 이 경우, AnyCancellable 객체를 따로 저장할 필요가 없습니다. 예를 들어:

    class MyViewModel: ObservableObject {
        @Published var someValue: Int = 0
        private var cancellable: AnyCancellable?
    
        init() {
            cancellable = somePublisher.assign(to: \.someValue, on: self)
        }
    }

     위의 코드에서 assign(to:on:) 메서드를 사용하여 somePublisher의 값을 someValue에 할당하고, 구독을 생성합니다. cancellable 변수는 AnyCancellable 타입으로 선언되었지만, assign(to:on:) 메서드에 의해 자동으로 해제됨.

Designed by Tistory.