Search code examples
iosswiftcombinepublisher

Swift Combine: direct output of one Publisher to the input of another


Consider the following synthetic scenario:

import Combine

let publisher1 = PassthroughSubject<Int, Never>().eraseToAnyPublisher()
let publisher2 = PassthroughSubject<Int, Never>()


publisher1.sink { value in
    publisher2.send(value)
}

We have 2 publishers, I'd like to propagate any value of the publisher1 to the publisher2. The code I've shown does the job, but I'm interested whether there is a cleaner, declarative approach to this.

Note: both publisher1 and publisher2 are of the same type.

Details on the problem

publisher2 is a part of the API that is exposed by the "core" class. The "core" class has a "has a" relationship to a "child" class which in turn has a publisher1 as it's API.

Over the lifetime of the "core" class, the "child" class can be allocated and deallocated multiple times. This should be transparent to the subscribers of the "core" class which won't need to subscribe to the publisher2.

Code:

import UIKit
import Combine


class ChildClass {
    let publisher1 = PassthroughSubject<Int, Never>().eraseToAnyPublisher()
}

class CoreClass {
    let publisher2 = PassthroughSubject<Int, Never>()

    private var childClass: ChildClass?

    init() {
        allocateChildClass()
    }

    func allocateChildClass() {
        let child = ChildClass()
        childClass = child
        // Any way to simplify this?
        child.publisher1.sink { value in
            publisher2.send(value)
        }
    }

    func deallocateChildClass() {
        childClass = nil
    }
}


class Client {
    let core = CoreClass()

    init() {
        // Doesn't care about allocating or deallocating of the ChildClass
        core.publisher2.sink { value in
            print(value)
        }
    }
}

Trying to subscribe one publisher to another doesn't work:

publisher2
    .subscribe(publisher1)

No exact matches in call to instance method 'subscribe'

enter image description here


Solution

  • It is a delightful feature of PassthroughSubject that it is both a publisher and an operator: a Subject can be chained directly to a pipeline.

    So just say

    publisher1.subscribe(publisher2)
    

    and you're all set.