Быстрое объединение: превратить издателя в CurrentValueSubject только для чтения - PullRequest
0 голосов
/ 30 апреля 2020

Иногда моя модель представления использует свойство @Published или PassthroughSubject, но я не хочу, чтобы это было доступно для записи во внешний мир. Достаточно просто, превратить его в publi c AnyPublisher и оставить доступным для записи один из них, например:

class ViewModel {
  @Published private var _models = ["hello", "world"]

  var models: AnyPublisher<[String], Never> {
    return $_models.eraseToAnyPublisher()
  }
}

let viewModel = ViewModel()
viewModel.models.sink { print($0) }

Но что, если вы хотите иметь возможность читать значение «по требованию» как хорошо? Например, для этой ситуации:

extension ViewController: UICollectionViewDelegate {
  func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    print(viewModel.models[indexPath.row])
  }
}

Очевидно, что приведенный выше код не работает.

Я думал об использовании CurrentValueSubject, но его значение также доступно для записи, плюс мне все равно трудно превратить Publisher в CurrentValueSubject.

Мое текущее решение состоит в том, чтобы добавить что-то подобное в viewmodel:

class ViewModel {
  @Published private var _models = ["hello", "world"]
  @Published var selectedIndex: Int?

  var models: AnyPublisher<[String], Never> {
    return $_models.eraseToAnyPublisher()
  }

  var selectedModel: AnyPublisher<String, Never> {
    return models.combineLatest($selectedIndex.compactMap { $0 }).map { value, index in
      value[index]
    }.eraseToAnyPublisher()
  }
}

let viewModel = ViewModel()
viewModel.models.sink { print($0) }

viewModel.selectedModel.sink { print($0) }
viewModel.selectedIndex = 1

Но немного сложнее добавить свойство selectedIndex, издатель selectedModel, установить selectedIndex и подписаться на издателя .. все потому, что я хочу иметь возможность читать текущее значение viewModel.models (и не иметь возможности записи).

Есть ли лучшие решения?

1 Ответ

1 голос
/ 30 апреля 2020

Почему бы вам просто не сохранить свойство @Published publi c, оставив его установщик закрытым? Это должно идеально соответствовать вашим требованиям, сохраняя при этом ваш код минимальным и чистым.

class ViewModel {
  @Published public private(set) var models = ["hello", "world"]
}

let viewModel = ViewModel()
viewModel.$models.sink { print($0) }
...