Как правильно подходить к решению операций сохранения с помощью Swift Combine? - PullRequest
0 голосов
/ 09 марта 2020

У меня классическая c ситуация, когда я хочу совершить какое-то действие только один раз. Например, обновите некоторый объект в базе данных, используя Swift Combine. Моя проблема в том, что я не знаю, как лучше всего сделать что-то только один раз. Как отписаться, когда обновление завершится?

Это фрагмент кода через слои, которые я сейчас использую:

ViewModel: let settingsModel: LocalSettingsModel

func saveLocalSettings(){
    let cancelable = settingsUseCase
                         .saveLocalSettings(localSettingsModel: settingsModel)
                         .sink(receiveCompletion: {_ in
                             print("Completed!!!")

                         }) { _ in
                             print("Result of Save operation!!!")
                         }
}

UseCase:

func saveLocalSettings(settings: LocalSettingsModel) -> AnyPublisher<LocalSettingsModel, Error> {
    return repository.saveLocalSettings(settings: settings)
}

Репозиторий:

    guard let realmSettings = LocalSettingsRealmModel(fromModel: settings) else {
            return Fail<LocalSettingsModel, Error>(error: .postconditionError(errorMessage: ""))
                .eraseToAnyPublisher()
        }

    return self.localDataSource
        .saveLocalSettings(localSettings: realmSettings)
        .receive(on: DispatchQueue.main)
        .subscribe(on: DispatchQueue.global())
        .mapError { (error) -> Error in
             // do error mapping
        }
        .compactMap { settings in
            return (LocalSettingsModel(fromModel: settings))
        }
        .eraseToAnyPublisher()

Источник данных:

func saveLocalSettings(localSettings: LocalSettingsRealmModel) -> AnyPublisher<LocalSettingsRealmModel, LocalDataSourceError> {
    do {
        return Just(try saveSettings(localSettings: localSettings))
            .mapError({ (Never) -> LocalDataSourceError in})
            .eraseToAnyPublisher()
    } catch let error as NSError {
        // return some error
    }
}

func saveSettings(localSettings: LocalSettingsRealmModel) throws -> LocalSettingsRealmModel
{
    let realm = try Realm()

    try realm.write {
        realm.add(localSettings, update: .modified)
    }

    return localSettings
}

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

1 Ответ

0 голосов
/ 13 марта 2020

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

Combine настроен для работы с одно ИЛИ много значений. Таким образом, вы, как потребитель, должны дать ему какой-то способ ограничить потенциально много значений одним значением, если вы хотите использовать assign подписчик для установки значения (или sink подписчик для вызова замыкания, где вы сохраните, в вашем случае).

Операторы последовательности в Combine - это то, где я бы хотел посмотреть, но я не могу действительно описать , который , не зная, сколько значений и как бы вы выбрали, какой из них применить. Два «простых» варианта: first или last, но существует множество операторов последовательности, которые позволяют создавать более сложные варианты (включая firstWhere и lastWhere, которые позволяют определять на основе вашего собственного закрытия, что может быть чертовски удобно.

Все встроенные ссылки относятся к онлайн / бесплатной версии Использование Combine (раскрытие: которое я написал) - и хотя у меня нет каких-либо явных примеров об операторах последовательности, я все же выложил sh справочные сведения для них в книге.

Если вы явно не работаете с издателем, вам может оказаться проще использовать библиотеку Promise - в зависимости от того, что вызывает ваше сохранение. Я не знаю, как закончится область Realm, чтобы знать, на чем сфокусирован их API, и если вы сделали издателя, который генерирует данные, или если они исходят из их API - и, следовательно, вы хотите использовать Combine для решения этой проблемы.

...