Объединить: нельзя использовать `.assign` со структурами - почему? - PullRequest
1 голос
/ 06 апреля 2020

При попытке присвоить значение с помощью Combine я вижу поведение структуры против класса, которое на самом деле не понимаю.

Код:

import Foundation
import Combine

struct Passengers {
  var women = 0
  var men = 0
}

class Controller {
  @Published var passengers = Passengers()
  var cancellables = Set<AnyCancellable>()
  let minusButtonTapPublisher: AnyPublisher<Void, Never>

  init() {
    // Of course the real code has a real publisher for button taps :)
    minusButtonTapPublisher = Empty<Void, Never>().eraseToAnyPublisher()

    // Works fine:
    minusButtonTapPublisher
      .map { self.passengers.women - 1 }
      .sink { [weak self] value in
        self?.passengers.women = value
      }.store(in: &cancellables)

    // Doesn't work:
    minusButtonTapPublisher
      .map { self.passengers.women - 1 }
      .assign(to: \.women, on: passengers)
      .store(in: &cancellables)
  }
}

я получаю ошибку Key path value type 'ReferenceWritableKeyPath<Passengers, Int>' cannot be converted to contextual type 'WritableKeyPath<Passengers, Int>'.

Версия, использующая sink вместо assign, работает нормально, и когда я превращаю Passengers в класс, версия assign также работает нормально. Мой вопрос: почему это работает только с классом? Две версии (тонуть и назначить) действительно делают одно и то же в конце, верно? Они оба обновляют свойство women в passengers.

(Когда я изменяю Passengers на класс, версия sink больше не работает.)

1 Ответ

0 голосов
/ 07 апреля 2020

На самом деле это явно задокументировано - Назначает каждый элемент из издателя свойству объекта . Это особенность, дизайн Assign подписчика - для работы только с ссылочными типами.

extension Publisher where Self.Failure == Never {

    /// Assigns each element from a Publisher to a property on an object.
    ///
    /// - Parameters:
    ///   - keyPath: The key path of the property to assign.
    ///   - object: The object on which to assign the value.
    /// - Returns: A cancellable instance; used when you end assignment of the received value. Deallocation of the result will tear down the subscription stream.
    public func assign<Root>(to keyPath: ReferenceWritableKeyPath<Root, Self.Output>, on object: Root) -> AnyCancellable
}
...