Swift Combine 创建一个自定义主题

Nun*_*ves 3 swift combine

我想要一个Subject(类似于CurrentValueSubject)我可以发布到,但这验证了我发送的值。例如,我想验证输入是否强制在一系列值之间,例如 1 和 10。如果高于最大值,则通过最大值,如果低于最小值,则通过最小值。

请不要告诉我在订阅代码上过滤结果,因为这是我试图避免的。那个重复。

伪代码将是:

let intSubject = ValidatedValueSubject<Int>(value: 5, min: 1, max: 10)

intSubject.sink { value in  print(value) }

intSubject.send(-10)
intSubject.send(5)
intSubject.send(15)
Run Code Online (Sandbox Code Playgroud)

我希望这样产生:

5
1
5
10
Run Code Online (Sandbox Code Playgroud)

显然用CurrentValueSubject我无法达到那种效果。我尝试创建自己的自定义主题,但似乎无法使其正常工作。

有人告诉我我应该以不同的方式看待我的问题,因为我想这太容易了,不需要自定义Subject.

用例:

我有一个设置类,它会在“设置”屏幕和其他任何地方更新,当值发生变化时,我希望屏幕做出相应的反应。在ValidatedValueSubject此设置中生活对象。

设置需要公开,Subject以便任何屏幕都可以对属性的更改做出反应。

我的习惯做法Subject如下:

5
1
5
10
Run Code Online (Sandbox Code Playgroud)

rob*_*off 7

你可以包装一个CurrentValueSubject

class MySubject<Output, Failure: Error>: Subject {
    init(initialValue: Output, groom: @escaping (Output) -> Output) {
        self.wrapped = .init(groom(initialValue))
        self.groom = groom
    }

    func send(_ value: Output) {
        wrapped.send(groom(value))
    }

    func send(completion: Subscribers.Completion<Failure>) {
        wrapped.send(completion: completion)
    }

    func send(subscription: Subscription) {
        wrapped.send(subscription: subscription)
    }

    func receive<Downstream: Subscriber>(subscriber: Downstream) where Failure == Downstream.Failure, Output == Downstream.Input {
        wrapped.subscribe(subscriber)
    }

    private let wrapped: CurrentValueSubject<Output, Failure>
    private let groom: (Output) -> Output
}
Run Code Online (Sandbox Code Playgroud)

并像这样使用它:

let subject = MySubject<Int, Never>(initialValue: 5) { max(1, min($0, 10)) }
let ticket = subject.sink { print("value: \($0)") }
subject.send(-10)
subject.send(5)
subject.send(15)
Run Code Online (Sandbox Code Playgroud)

输出:

class MySubject<Output, Failure: Error>: Subject {
    init(initialValue: Output, groom: @escaping (Output) -> Output) {
        self.wrapped = .init(groom(initialValue))
        self.groom = groom
    }

    func send(_ value: Output) {
        wrapped.send(groom(value))
    }

    func send(completion: Subscribers.Completion<Failure>) {
        wrapped.send(completion: completion)
    }

    func send(subscription: Subscription) {
        wrapped.send(subscription: subscription)
    }

    func receive<Downstream: Subscriber>(subscriber: Downstream) where Failure == Downstream.Failure, Output == Downstream.Input {
        wrapped.subscribe(subscriber)
    }

    private let wrapped: CurrentValueSubject<Output, Failure>
    private let groom: (Output) -> Output
}
Run Code Online (Sandbox Code Playgroud)