Property Wrapper для CurrentValueSubject - управление памятью

Я хотел бы создать property wrapper за CurrentValueSubject. Я сделал вот так:

@propertyWrapper
public class CurrentValue<Value> {

    public var wrappedValue: Value {
        get { projectedValue.value }
        set { projectedValue.value = newValue }
    }

    public var projectedValue: CurrentValueSubject<Value, Never>

    public init(wrappedValue: Value) {
        self.projectedValue = CurrentValueSubject(wrappedValue)
    }

}

Это работает, но есть кое-что, что я хотел бы изменить с помощью этого - используйте структуру вместо класса. Проблема с использованием структуры для этого в том, что иногда я мог получитьSimultaneous accessesошибка. И я знаю, почему это происходит, когда вsinkот этого издателя я бы попытался прочитать значение из завернутого значения. Так, например, с таким кодом:

@CurrentValue
let test = 1
$test.sink { _ in
    print(self.test)
} 

И я более-менее знаю почему - потому что когда projectedValueвыполняет свое наблюдение, обернутое значение все еще находится в процессе установки своего значения. В классе это нормально, потому что он просто изменит значение, но со структурой он фактически изменяет саму структуру, поэтому я пытаюсь писать и читать из нее одновременно.

Мой вопрос - есть ли какой-нибудь умный способ преодолеть это, все еще используя структуру? Я не хочуdispatch async.

Также я знаю, что @Projected работает аналогично этому propertyWrapper, но есть большая разница - Projected выполняется на willSet, пока CurrentValueSubject на didSet. А такжеProjected в любом случае имеет ту же проблему.

Я знаю, что могу прочитать значение внутри закрытия, но иногда я использую это с различными вызовами функций, которые в конечном итоге могут использовать self.test вместо.

1 ответ

Попробуйте мою реализацию

      @propertyWrapper
class PublishedSubject<T> {
    
    var wrappedValue: T {
        didSet {
            subject.send(wrappedValue)
        }
    }
    
    var projectedValue: some Publisher<T, Never> {
        subject
    }
    
    private lazy var subject = CurrentValueSubject<T, Never>(wrappedValue)
    
    init(wrappedValue: T) {
        self.wrappedValue = wrappedValue
    }
}
Другие вопросы по тегам