2017-02-27 49 views
0

我試圖將RxSwift添加到使用MVVM模式的代碼和平。我的應用程序需要從API獲取FoodType(沙漠,膳食等)食物列表並將它們保存到Realm數據庫。然後,我有一個UITextField和一個UIButton的視圖。使用RxSwift異步API調用後更新視圖

用戶寫食品的一個種類(例如:沙漠):

  • 背景:應用程序如果不是在境界應該從AP獲得食物類型和FoodList DB
  • 在按鈕點擊:食品展示列表已在食物類型從境界

視圖模型

struct FoodTypeViewModel { 

    // Get datas from API 
    private func getFoods() { 
     foodService.getAll(completionHandler: { result in 
      switch result { 
      case .Success(let foods): 
       for food in foods { 
        food.save() 
       } 
       break 
      case .Failure(let error): 
       debugPrint(error) 
       break 
      } 
     }) 
    } 

    // Get datas from API 
    private func getFoodTypes() { 
     foodService.getAll(completionHandler: { result in 
      switch result { 
      case .Success(let foodTypes): 
       for type in types { 
        type.save() 
       } 
       break 
      case .Failure(let error): 
       debugPrint(error) 
       break 
      } 
     }) 
    } 
} 
選擇由用戶

的ViewController

class SetupViewController: UIViewController { 
     @IBOutlet weak var foodTypeTextField: UITextField! 
     @IBOutlet weak var foodTypeButton: UIButton! 
} 

型號

class FoodType: Object { 
    dynamic var identifier: String = "" 
    dynamic var fullName: String? 
    let foods = List<Food>() 
} 

我想RxSwift添加到代碼,但我怎麼能處理異步API。在第一次啓動應用程序沒有數據(我不想在開始時填充),但當用戶單擊按鈕。所以在按鈕點擊時,UI應該等待來自服務的響應(使用等待動畫),並且ViewModel應該在服務響應時更新UI。任何想法 ?

回答

1

首先,創建一個通用返回對象來包裝通信錯誤。

enum APIResult<T> { 
    case success(T) 
    case error(Error) 
} 

然後,將您完成處理程序返回一個Observable

func getFoods() -> Observable<APIResult<[FoodType]>> { 
    return Observable<APIResult<[FoodType]>>.create { observer -> Disposable in 
     self.foodService.getAll(completionHandler: { result in 
      switch result { 
      case .Success(let foods): 
       observer.onNext(.success(foods)) 
       break 
      case .Failure(let error): 
       observer.onNext(.error(error)) 
       break 
      } 
      observer.onCompleted() 

      return Disposables.create() 
     }) 
    } 
} 

現在簡單地處理觀察到任何其他的RxSwift。

getFoods().subscribe(onNext: { result in 
    switch result { 
     case .success(let foods): 
      print("Received foods: \(foods)") 
      break 
     case .error(let error): 
      print("Received error: \(error)") 
      break 
    } 
}.addDisposableTo(disposeBag) 

使用these utility classes會幫助你取得成功的結果和分裂的錯誤和成功的信號映射到不同的觀測。例如:

let foodsRequest = getFoods().splitSuccess 

foodsRequest.error.subscribe(onNext: { error in 
    print("Received error: \(error)") 
}) 

foodsRequest.success.subscribe(onNext: { foods in 
    print("Received foods: \(foods)") 
} 

你也可以轉換境界反對RxSwift觀測:

let realm = try! Realm() 
realm.objects(Lap).asObservable() 
    .subscribeNext {[weak self] laps in 
    self?.tableView.reloadData() 
    } 

看看Using Realm Seamlessly in an RxSwift App的更多信息和示例。

+0

謝謝,但它是處理領域的最佳方式?我的意思是,我相信有一種方法可以在應用程序生命中只使用本地存儲。該API只與DB進行通信並且視圖對DB更改作出反應。在你的情況下,我應該等待API的數據。你明白我的意思嗎 ?順便說一句,感謝這個非常好的答案和課程! – Ludovic

+1

@Ludovic您也可以將本地數據庫更改綁定爲可觀察對象。看看我的編輯。 – redent84

+0

謝謝你的回答! – Ludovic