10

私は最近 ReactiveCocoa v3 を読んでいて、基本的なものを設定するだけで苦労しています。私はすでに変更ログ、テスト、いくつかの SO の質問、およびこの件に関する Colin Eberhardt の記事を読みました。ただし、基本的なバインディングの例はまだありません。

その日のメニューを表示するアプリがあるとします。アプリは RAC3 と MVVM パターンを使用しています。

モデル(メニュー)

このモデルには、今日のメニューを取得するための簡単なメソッドが 1 つあります。今のところ、これはネットワーク リクエストを行わず、基本的にはモデル オブジェクトを作成するだけです。mainCourseプロパティはString.

class func fetchTodaysMenu() -> SignalProducer<Menu, NoError> {
    return SignalProducer {
        sink, dispoable in
            let newMenu = Menu()
            newMenu.mainCourse = "Some meat"
            sendNext(sink, newMenu)
            sendCompleted(sink)
    }
}

ビューモデル (MenuViewModel)

ビュー モデルはString、ビュー コントローラーにメニューを表示させるためのさまざまな変数を公開します。メインコースを表示するためのプロパティを 1 つだけ追加しましょう。

var mainCourse = MutableProperty("")

そして、このプロパティのバインディングを追加します:

self.mainCourse <~ Menu.fetchTodaysMenu()
    |> map { menu in
        return menu.mainCourse!
    }

ViewController (MenuViewController)

最後になりましたが、このメイン コースをビューで紹介したいと思います。これに a を追加しますUILabel

var headline = UILabel()

text最後に、ビュー モデルを観察して、その UILabelのプロパティを設定したいと思います。次のようなもの:

self.headline.text <~ viewModel.headline.producer

残念ながらこれは機能しません。

質問

  1. このメソッドfetchTodaysMenu()は を返しますが、代わりにSignalProducer<Menu, NoError>このメソッドが を返すようにしたい場合はどうすればよいでしょうか? SignalProducer<Menu, NSError>これにより、メソッドがエラーを返す可能性があるため、ビュー モデルでのバインディングが失敗します。どうすればこれを処理できますか?
  2. 前述のように、ビュー コントローラーの現在のバインディングが機能しません。のプロパティMutablePropertyを表すを作成して遊んでいますが、うまくいきませんでした。また、バインドしたいプロパティごとに追加の変数を作成しなければならないのは、ぎこちなく、冗長に感じると思います。これは RAC2 では必要ありませんでした。私も意図的に の使用を避けようとしましたが、そうすべきではないでしょうか? 私は基本的に、正しいやり方を見つけたいだけです。textUILabelDynamicPropertyRAC(self.headline, text) = RACObserve(self.viewModel, mainCourse);

この基本的なセットアップを行う方法に関するその他のフィードバック/ガイダンスは大歓迎です。

4

1 に答える 1

13

この質問を書いた後、Colin Eberhardt は RAC3 ブログ投稿シリーズのパート 3 を作成しました。これには、MVVM と RAC3 を使用する興味深い非常に関連性の高い例が含まれています。投稿はこちらから、ソースコードはこちらからご覧いただけます

彼の仕事に基づいて、私は自分の質問に答えることができました:

  1. 少し違うアプローチをとることで、思い通りのfetchTodaysMenu()リターンにすることができSignalProducer<Menu, NSError>ます。ビューモデルで次に行うことは次のとおりです。

    MenuService.fetchTodaysMenu()
        |> observeOn(QueueScheduler.mainQueueScheduler)
        |> start(next: { response in
            self.mainCourse.put(response.mainCourse!)
        }, error: {
            println("Error \($0)")
        })
    
  2. UIKitRAC3 ベータ 4 の時点では、まだバインディングはないようです。Colin は、私が探していたこれらのバインディングを作成するのを助けるために、いくつかの拡張UIKit機能を自分で作成しました。これらはここにあります。それらを私のプロジェクトに追加すると、私がやりたかったことを正確に実行できるようになりました:

    self.mainCourse.rac_text <~ self.viewModel.mainCourse
    

2015 年 5 月 25 日更新

ReactiveCocoa 3 でさらに多くの作業を行った後、もう一度 1) に答えたいと思います。を使用するcatchと、より宣言的な方法でこれを行うことができます。私はこれのために小さなヘルパー関数を実装することになりました:

public func ignoreError<T: Any, E: ErrorType>(signalProducer: SignalProducer<T, E>) -> SignalProducer<T, NoError> {
    return signalProducer
        |> catch { _ in
            SignalProducer<T, NoError>.empty
        }
}

この関数は、任意のNSErrorを に変換しNoErrorて、思い通りにバインドできるようにしMenuService.fetchTodaysMenu() |> ignoreErrorます。

これは、ReactiveCocoa 3.0 を検討している他の人にとって良い出発点になる可能性があるため、プロジェクトをオープンソース化しました: https://github.com/s0mmer/TodaysReactiveMenu

2016 年 3 月 5 日更新

コメントで強調されているように、Swift 2 以降、ignoreError関数は次のようになります。

public func ignoreError() -> SignalProducer<Value, NoError> {
    return flatMapError { _ in
        SignalProducer<Value, NoError>.empty
    }
}

また、 Rexという拡張ライブラリも作成されており、同様のものが追加されています。

于 2015-05-18T15:50:55.850 に答える