Как я могу разделить сигнал и снова объединить его позже?

Я не совсем уверен, как это сделать правильно, и я, вероятно, упускаю некоторые понятия о FRP, так как я не так давно играю с ReactiveCocoa.

Моя ситуация такова - у меня есть сигналы, которые:

  • загружает объект из локального хранилища;
  • загружает объект из удаленного хранилища;
  • сохраняет удаленный объект в локальном хранилище;
  • преобразует (сопоставляет) объект из локального хранилища в другой формат

Я хочу иметь один сигнал, на который я могу подписаться, который будет:

  • загрузить объект по localId из локального хранилища;
  • split signals here, to:
    • send an initial object to the signal's subscriber:
      • transform the object into a different format;
      • отправить этот формат конечному абоненту;
    • update the local object from a remote store and send the updated version;
      • load an object from a remote store using a remoteId from the local object just loaded;
      • сохранить этот удаленный объект в локальном хранилище;
      • перезагрузить объект из локального хранилища с исходного localId;
      • преобразовать объект в другой формат;
      • отправить этот формат конечному абоненту;
      • завершить сигнал.

Идея, стоящая за всем этим, заключается в том, что мой основной сигнал объекта загрузки должен возвращать начальную версию объекта (сохраненную локально), при этом обновляя этот объект из удаленного хранилища и, наконец, отправляя обновленную версию. Таким образом, конечный подписчик должен получить объект дважды перед завершением.

Сигнал удаленной загрузки зависит от сигнала локальной загрузки, потому что мы должны загрузить локальный объект, чтобы получить remoteId для объекта. Поэтому я хотел бы избежать двойной загрузки локального объекта (один раз для отправки исходному подписчику и один раз для получения remoteId для загрузки удаленного объекта) при запуске сигнала.

Первоначальное решение, которое я придумал, состояло в том, чтобы сделать локальный сигнал загрузки многоадресным (autoconnected) сигналом, а затем объединить этот сигнал (с преобразованием, связанным с ним) с тем же сигналом (с удаленной загрузкой, сохранением, загрузкой и преобразованием, связанными с Это). Однако это никогда не переходит к удаленной загрузке, что, как я могу предположить, связано только с отправкой сигнала локальной загрузки completed.

Есть ли способ сделать то, что я хочу сделать? У меня неправильная логика? Спасибо заранее за любые предложения.


person Rupert    schedule 09.01.2015    source источник


Ответы (1)


Одной из возможностей было бы использовать Subject. Если вы не знакомы, на Subject можно подписаться, как и на обычный Signal, но вы можете явно указать ему отправлять значения (или ошибки, или завершенные сообщения). Вы также можете подписаться на субъект на сигнал, и субъект будет распространять сообщения этого сигнала среди своих подписчиков.

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

let subject = RACSubject()

subject.map {
    let localObject = $0 as! LocalObjectType
    return transformLocalFormToFinalForm(localObject)
}
.subscribeNext { 
    let finalObject = $0 as! FinalObjectType
    // Process your final object here
}


let localObjectId = ... // Assuming the ID exists

getLocalObject(localObjectId).doNext { 
    subject.sendNext($0) 
}
.flattenMap {
    let localObject = $0 as! LocalObjectType
    return getRemoteObject(localObject.remoteId)
}
.flattenMap {
    let remoteObject = $0 as! RemoteObjectType
    return saveRemoteObjectToLocalStore(remoteObject)
}
.flattenMap {
    return getLocalObject(localObjectId)
}
.subscribeNext({
    subject.sendNext($0)
    subject.sendCompleted()
}, error {
    subject.sendError($0)
})

Эта установка должна выполнять следующие действия:

  1. Получить локальный объект из идентификатора
  2. Отправьте локальный объект субъекту (он преобразуется и отправляется конечному подписчику)
  3. Используйте удаленный идентификатор из локального объекта, чтобы получить удаленный объект
  4. Сохраните удаленный объект в локальном хранилище
  5. Получить (теперь обновленный) локальный объект из исходного идентификатора
  6. Отправить локальный объект и завершенное сообщение в тему (или ошибку, если ошибка возникает где-то в цепочке)

Надеюсь это поможет!

person Eric    schedule 26.06.2015