[Swift] Combine에서 RxSwift의 methodInvoked 사용하기

2023.10.27 updated: https://github.com/CombineCommunity/CombineCocoa/pull/88

현재 위의 PR에서 원래 개발자분이 CombineCocoa에 해당 기능이 들어갈지 말지 논의중입니다. 이왕이면 위 PR이 머지되고 CombineCocoa를 사용하세요!

Combine 프레임워크로 개발을 하다보면 코드를 더 깔끔하게 만들기 위해 RxSwift에서 사용했던 methodInvoked(_:) 메소드를 쓰고 싶은 니즈가 생긴다.

나와 같은 니즈를 가진 사람이 분명히 있을 것 같아 CombineCocoa 라이브러리에서 찾아보았는데 DelegateProxy 까지는 있지만, methodInvoked(_:) 함수는 없었다…

대신 CombineCocoa의 Issues에서 누군가 구현한 자료가 있었다. #

그래서 코드를 확인해보니 굳이 CombineCocoa와 같이 엮일 필요는 없을 것 같아 따로 분리시켜 내가 다시 만들었다. #

import UIKit
import Combine
import CombineInterception

extension UIViewController {
    var viewDidLoadPublisher: AnyPublisher<Void, Never> {
        let selector = #selector(UIViewController.viewDidLoad)
        return publisher(for: selector)
            .map { _ in () }
            .eraseToAnyPublisher()
    }
    
    var viewWillAppearPublisher: AnyPublisher<Bool, Never> {
        let selector = #selector(UIViewController.viewWillAppear(_:))
        return intercept(selector)
            .map { $0[0] as? Bool ?? false }
            .eraseToAnyPublisher()
    }
}

class ViewController: UIViewController {
    private var subscriptions = Set<AnyCancellable>()
    
    private func bind() {
        viewDidLoadPublisher
            .sink(receiveValue: { _ in
                print("viewDidLoad")
            })
            .store(in: &subscriptions)
        
        viewWillAppearPublisher
            .sink(receiveValue: { isAnimated in
                print("viewWillAppearPublisher", isAnimated)
            })
            .store(in: &subscriptions)
    }
}

혹시라도 Combine으로 개발중인 프로젝트가 있고, methodInvoked(_:) 함수를 써야하는 일이 생긴다면 SPM으로 https://github.com/chorim/CombineInterception.git 를 설치해서 위처럼 사용하면 된다!