2016-01-08 6 views
10

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

То, что я сделал, является предметом переменной, а затем позволяет моим моделям слушать это. ParseService:

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

MushroomLibraryModel:

_ = 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) 
    }) 

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

ParseService:

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 

SyncViewModel:

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

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

Приветствия!

ответ

7

Хм ... Вот статья об использовании переменных (обратите внимание, что переменный является оберткой 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 для извлечения грибов и их кеширования. С этого момента он просто вернет прежние кашированные грибы.

+0

Удивительный и спасибо за ответ :) Как насчет части состояния синхронизации? В основном у меня есть класс обслуживания, который выполняет кучу материала до тех пор, пока библиотека не будет синхронизирована. Этот метод syncLibrary() вызывается при запуске приложения, но я хочу, чтобы несколько классов могли прослушивать состояние синхронизации в случае появления новых грибов. У меня также есть начальный экран, на котором я показываю ход синхронизации. Вы также сделали бы syncLibrary var? Это приложение btw на тот случай, если он объяснит, что я делаю goo.gl/xJaV0d, это уже я просто пытаюсь овладеть RxSwift, он продолжает дуть мне в голову. – Manny

+0

Cool looking app.Как и в статье, на которую я ссылаюсь, вы редко нуждаетесь в предметах (включая переменную). Я думаю, что они в основном находятся в библиотеке в те времена, когда у вас есть что-то, например, вместо делегата, rx поток. –

+0

В случае синхронизации ваш код DB уже должен быть завернут, чтобы он возвращал наблюдаемые. Мне нравится то, что я сделал выше для PFObject. Субъекты предназначены для создания горячих наблюдаемых из ничего. Ваша БД не должна генерировать горячие наблюдаемые. –