Простой код, быстро переходящий к реактивному

Люди, как я могу конвертировать мой код:

struct CarModel {
    var model: String?
    var make: String?
    var kilowatts: Int?
    var photoURL: String?

    init(model: String, make: String, kilowatts: Int, photoURL: String) {
        self.model = model
        self.make = make
        self.kilowatts = kilowatts
        self.photoURL = photoURL
    }
} 

а также:

class CarViewModel {
    private var car: Car?

    static let HPperKW = 1.34102209

    var modelText: String? {
        return car?.model
    }
    var makeText: String? {
        return car?.make
    }
    var horsepowerText: String? {
        guard let kilowatts = car?.kilowatts else { return nil }
        let HP = Int(round(Double(kilowatts) * CarViewModel.HPperKW))
        return "\(HP) HP"
    }
    var titleText: String? {
        guard let make = car?.make, let model = car?.model else { return nil }
        return "\(make) \(model)"
    }
    var photoURL: URL? {
        guard let photoURL = car?.photoURL else { return nil }
        return URL(string: photoURL)
    }

    init(_ car: Car) {
        self.car = car
    }
}

в ReactiveCocoa/ReactiveSwift. Я зачитал. документация о Reactive, но я не понял, как я могу реализовать Reactive API для моего кода. Кто знает, как мне нужно это сделать, скажите, пожалуйста. И еще тот, кто знает хорошие образцы / примеры / учебники для последней версии ReactiveCocoa / ReactiveSwift, пожалуйста, скажите мне.

1 ответ

Решение

ReactiveCocoa предназначен для привязки динамических данных (хранящихся в вашей модели представления) к пользовательскому интерфейсу ViewController. Если ваши данные не являются динамическими (если viewmodel не изменяется в течение срока службы viewcontroller), вам вообще не нужно использовать реактивный код. Однако, если ваш car переменная изменится, и для отображения нескольких автомобилей будет использоваться один viewcontroller, реагирующий на это будет очень полезен. Вы можете использовать MutableProperty класс для инкапсуляции динамического car переменная и создает сигналы, которые будут обновлять ViewController при каждом изменении свойства автомобиля.

class CarViewModel {
  let car: MutableProperty<Car>

  init(_ car: Car) {
    self.car = MutableProperty(car)
  }

  var modelTextSignal: SignalProducer<String, NoError> {
    return car.producer.map { $0.model }
  }

  var makeTextSignal: SignalProducer<String, NoError> {
    return car.producer.map { $0.make }
  }

  var horsepowerTextSignal: SignalProducer<String, NoError> {
    return car.producer.map { car in
      let HP = Int(round(Double(car.kilowatts) * CarViewModel.HPperKW))
      return "\(HP) HP"
    }
  }

  var titleTextSignal: SignalProducer<String, NoError> {
    return car.producer.map {  "\($0.make) \($0.model)" }
  }

  var photoURLSignal: SignalProducer<URL?, NoError> {
    return car.producer.map { URL(string: $0.photoURL) }
  }
}

Теперь у нас есть куча сигналов, которые представляют собой изменение car данные с течением времени, и может использовать ReactiveCocoa для привязки этих сигналов к пользовательскому интерфейсу, так что пользовательский интерфейс автоматически обновляется с новыми данными автомобиля каждый раз viewModel.car.value обновляется!

class CarViewController: UIViewController {
  @IBOutlet modelLabel: UILabel!
  @IBOutlet makeLabel: UILabel!
  @IBOutlet horsepowerLabel: UILabel!
  @IBOutlet titleLabel: UILabel!
  @IBOutlet image: UIImageView!

  var viewModel: CarViewModel!

  override func viewDidLoad() {
    self.modelLabel.reactive.text <~ self.viewModel.modelTextSignal
    self.makeLabel.reactive.text <~ self.viewModel.makeTextSignal
    self.horsepowerLabel.reactive.text <~ self.viewModel.horsepowerTextSignal
    self.titleLabel.reactive.text <~ self.viewModel.titleTextSignal
    self.viewModel.photoURLSignal.startWithValues { [weak self] url in
      self?.setImageFromUrl(url)
    }
  }

  func displayNewCar() {
    self.viewModel.car.value = aRandomCar()
  }

  private func setImageFromUrl(url: URL?) {
    //download url and display in UIImageView
  }
  private func aRandomCar() -> Car {
    //return a Car object
  }
}

Таким образом, вы можете видеть, что если вам нужно отображать только один неизменяемый автомобильный объект в вашем контроллере представления, ReactiveCocoa не требуется - однако, если ваша viewmodel меняется в течение всего срока службы viewcontroller, реактивное кодирование позволяет связывать изменяемые данные. в пользовательский интерфейс, так что ваши взгляды автоматически обновляются при изменении данных!

Другие вопросы по тегам