You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中能否为CustomPublisher类定义Setter实现直接赋值?

问题:如何让CustomPublisher支持直接赋值替代send方法

我实现了一个类似@Published的不可完成版CurrentValueSubject(CustomPublisher类),现在想不用调用.send(value),而是通过定义Setter,实现直接用customPublisher = newValue的方式完成赋值,请问这可行吗?

原调用方式:

customPublisher.send(newValue)

目标调用方式:

customPublisher = newValue

原自定义类代码:

final class CustomPublisher<Output: Any>: Publisher {
    typealias Failure = Never

    var value: Output
    private var wrapper: CurrentValueSubject<Output, Failure>

    init(_ value: Output) {
        self.value = value
        wrapper = .init(value)
    }

    func send(_ value: Output) {
        self.value = value
        wrapper.send(value)
    }

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

    func receive<S>(subscriber: S) where S: Subscriber, Failure == S.Failure, Output == S.Input {
        wrapper.receive(subscriber: subscriber)
    }
}

解决方案

直接通过customPublisher = newValue的语法触发原实例的send逻辑不可行,因为CustomPublisher是类(引用类型),这种赋值操作会直接替换整个实例的引用,而非修改现有实例的内部状态。不过可以通过以下几种方式实现类似的简洁赋值效果:

方式一:利用value属性的Setter触发发送

修改value属性的Setter,在赋值时自动调用send方法,只需给value赋值就能完成发送,语法接近目标需求:

final class CustomPublisher<Output: Any>: Publisher {
    typealias Failure = Never

    var value: Output {
        didSet {
            wrapper.send(value)
        }
    }
    private var wrapper: CurrentValueSubject<Output, Failure>

    init(_ value: Output) {
        self.value = value
        wrapper = .init(value)
    }

    func send(_ value: Output) {
        self.value = value
    }

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

    func receive<S>(subscriber: S) where S: Subscriber, Failure == S.Failure, Output == S.Input {
        wrapper.receive(subscriber: subscriber)
    }
}

调用方式:

customPublisher.value = newValue

方式二:改为结构体(值类型)实现直接赋值

将CustomPublisher改为结构体,利用值类型的赋值特性,在赋值时触发内部状态更新并发送事件:

struct CustomPublisher<Output: Any>: Publisher {
    typealias Failure = Never

    private var wrapper: CurrentValueSubject<Output, Failure>

    var value: Output {
        get { wrapper.value }
        set { wrapper.send(newValue) }
    }

    init(_ value: Output) {
        wrapper = .init(value)
    }

    func send(_ value: Output) {
        wrapper.send(value)
    }

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

    func receive<S>(subscriber: S) where S: Subscriber, Failure == S.Failure, Output == S.Input {
        wrapper.receive(subscriber: subscriber)
    }

    // 重载赋值运算符,确保赋值时更新内部状态
    static func = (lhs: inout CustomPublisher, rhs: Output) {
        lhs.value = rhs
    }
}

调用方式:

var customPublisher = CustomPublisher(initialValue)
customPublisher = newValue

方式三:实现为属性包装器(最接近@Published的用法)

如果场景和@Published类似,希望给属性添加发布能力,可以将CustomPublisher改为属性包装器:

@propertyWrapper
struct CustomPublisher<Output: Any>: Publisher {
    typealias Failure = Never

    private var wrapper: CurrentValueSubject<Output, Failure>

    var wrappedValue: Output {
        get { wrapper.value }
        set { wrapper.send(newValue) }
    }

    var projectedValue: some Publisher {
        wrapper
    }

    init(wrappedValue value: Output) {
        wrapper = .init(value)
    }

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

    func receive<S>(subscriber: S) where S: Subscriber, Failure == S.Failure, Output == S.Input {
        wrapper.receive(subscriber: subscriber)
    }
}

使用方式:

class ViewModel {
    @CustomPublisher var name: String = "Initial"
}

let vm = ViewModel()
vm.name = "New Value" // 自动触发发送

内容的提问来源于stack exchange,提问作者Petter Braka

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 06:05:22