RxSwift правильно использует переменные

Я пытаюсь преобразовать проект для использования RxSwift и MVVM. У меня есть служба, которая синхронизирует список данных из Parse при каждом запуске приложения, и я в основном хочу убедиться, что использую правильный подход.

Что я сделал, так это сделал переменную тему, а затем позволил моим моделям слушать это. ПарсСервис:

let rx_parseMushrooms = Variable<[ParseMushroom]>([])

Грибная библиотекаМодель:

_ = parseService.rx_parseMushrooms
    .asObservable()
    .map { (parseMushrooms:[ParseMushroom]) -> [Mushroom] in
        let mushrooms = parseMushrooms.map { (parseMushroom:ParseMushroom) -> Mushroom in
            let mushroom = Mapper<Mushroom>().map(parseMushroom.dictionaryWithValuesForKeys(parseMushroom.allKeys()))
            return mushroom!
        }

        return mushrooms
    }
    .subscribeNext({ (mushrooms:[Mushroom]) -> Void in
        self.mushrooms = mushrooms
        print(mushrooms)
    })

Я делаю то же самое для выражения состояния синхронизации.

ПарсСервис:

struct SyncState {
    enum State {
        case Unsynced, ConnectingToServer, SyncingInfo, FetchingImageList, SyncingImages, SyncComplete, SyncCompleteWithError
    }

    var infoToSync = 0
    var imagesToSync = 0
    var imagesSynced = 0

    var state = State.Unsynced
}

let rx_syncState = Variable(SyncState())

Затем я обновляю переменную а-ля

self.rx_syncState.value = self.syncState

Синквевемодел:

_ = parseService.rx_syncState
     .asObservable()
     .subscribeNext { [weak self] (syncState:ParseService.SyncState) -> Void in
          switch syncState.state {
              //show stuff based on state struct
          }
      }

В любом случае, я был бы очень признателен, если бы кто-нибудь сказал мне, хороший ли это способ сделать это или я неправильно использую RxSwift (и подскажет, как мне это делать).

Ваше здоровье!


person Manny    schedule 08.01.2016    source источник


Ответы (1)


Хм... Вот статья об использовании Variable (обратите внимание, что Variable является оболочкой BehaviorSubject.)

http://davesexton.com/blog/post/To-Use-Subject-Or-Not-To-Use-Subject.aspx

В вашем случае у вас уже есть холодная наблюдаемая (сетевой вызов), поэтому вам не нужна тема/переменная. Все, что вам нужно сделать, это опубликовать наблюдаемое, которое у вас уже есть, и использовать replay(1) для кэширования значения. Я бы ожидал, что класс с именем что-то вроде ParseServer будет содержать вычисляемое свойство с именем что-то вроде mushrooms.

Чтобы помочь вывести грибы из синтаксического анализа, вы можете использовать это (это создаст необходимое холодное наблюдаемое):

extension PFQuery {

    var rx_findObjects: Observable<[PFObject]> {
        return Observable.create { observer in
            self.findObjectsInBackgroundWithBlock({ results, error in
                if let results = results {
                    observer.on(.Next(results))
                    observer.on(.Completed)
                }
                else {
                    observer.on(.Error(error ?? RxError.Unknown))
                }
            })
            return AnonymousDisposable({ self.cancel() })
        }
    }

}

И тогда у вас будет что-то вроде:

class ParseServer {
    var mushrooms: Observable<[Mushroom]> {
        return PFQuery(className: "Mushroom").rx_findObjects
        .map { $0.map { Mushroom(pfObject: $0) } }
        .publish()
        .replay(1)
    }
}

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

Идея, однако, заключается в том, что при первом вызове myParseServer.mushrooms система вызовет Parse, чтобы получить грибы и кэшировать их. С этого момента он просто вернет предыдущие обналиченные грибы.

person Daniel T.    schedule 23.02.2016
comment
Круто и спасибо за ответ :) А как насчет части состояния синхронизации? По сути, у меня есть класс обслуживания, который делает кучу вещей, пока библиотека не будет синхронизирована. Этот метод syncLibrary() вызывается при запуске приложения, но я хочу, чтобы несколько классов могли прослушивать состояние синхронизации в случае появления новых грибов. У меня также есть начальный экран, на котором я показываю ход синхронизации. Не могли бы вы также сделать syncLibrary переменной? Кстати, это приложение на случай, если оно лучше объясняет, что я делаю goo.gl/xJaV0d, оно уже вышло, я просто пытаюсь освоить RxSwift, оно продолжает сносить мне мозг. - person Manny; 25.02.2016
comment
Классно выглядящее приложение. Как говорится в статье, на которую я ссылался, вам редко нужны темы (включая переменные). Я думаю, что они в основном находятся в библиотеке для тех случаев, когда у вас есть что-то, что, например, принимает делегат вместо обратного вызова, и вы хотите преобразовать это в поток rx. - person Daniel T.; 25.02.2016
comment
В случае синхронизации ваш код БД уже должен быть обернут так, чтобы он возвращал наблюдаемые объекты. Вроде того, что я сделал выше для PFObject. Субъекты предназначены для создания горячих наблюдаемых из ничего. Ваша БД не должна генерировать горячие наблюдаемые. - person Daniel T.; 25.02.2016
comment
Ага. Думаю, я все еще ломаю голову над горячими и холодными наблюдаемыми. Это имеет смысл. Спасибо еще раз - person Manny; 25.02.2016
comment
Простой способ подумать об этом. Когда вы подписываетесь на горячую наблюдаемую, все, что она делает, это добавляет наблюдателя в свой список наблюдателей. Когда вы подписываетесь на холодный наблюдаемый объект, он добавляет наблюдателя в список и запускает какой-то процесс. Так, например, UIButton.rx_tap — горячий, PFQuery.rx_findObjects в моем коде выше — холодный (для каждой подписки делается новый вызов сервера). - person Daniel T.; 25.02.2016