2017-01-11 6 views
0

私は、変数が更新されたときにUIを自動的に更新する簡単な方法を探していました。 Regular KVOはあまりにも面倒なコードなので、RxSwift、ReactiveCocoaなどを見てきましたが、これは把握が難しく、新しいオブジェクトがたくさんあり、必要のないものがたくさんありました。変数のdidSetの中にオプションの関数を呼び出すことは悪い習慣ですか?

変数のdidSetと、私のオブジェクトにemtpyオプションの関数を一緒に使って遊んでいます。うまくいけば、それが説明するよりも表示するように簡単です:

カスタムオブジェクト(ViewModelに)

class AwesomeViewModel{ 
    var awesomeText:String { didSet { updateBlock?() } } 
    var updateBlock:(()->())? 

    init(awesomeText:String){ 
     self.awesomeText = awesomeText 
    } 
} 

とカスタムUIViewの:

class AwesomeView:UIView{ 
    @IBOutlet weak var awesomeLabel: UILabel! 

    func bindViewModel(viewModel:AwesomeViewModel){ 
     viewModel.updateBlock = { [weak self] in 
      self?.awesomeLabel.text = viewModel.awesomeText 
     } 
     viewModel.updateBlock?() 
    } 
} 

のは、このカスタムビューAwesomeViewUIViewControllerように存在するとしましょうアウトレット。 AwesomeViewModelのインスタンスを作成し、self.awesomeView.bindViewModel(awesomeViewModel)を呼び出します。私は後に、私のUIViewControllerに(またはどこか他の、そのことについては、それが周りに渡すことができる)

awesomeViewModel.awesomeText = "Hello World"ような何かを、その後のViewModelの変数のdidSetはオプション機能updateBlockをトリガします。この機能はカスタムビューAwesomeViewによって設定されているため、そのビュー内のラベル内のテキストを自動的に更新します。

私はこれがかなりクールで理解しやすいと思っていましたが、これの副作用や私が見ていないものはありますか?それは悪い習慣ですか?それは私がbindViewModel()cellForRowAtIndexPathで呼び出されますUITableViewCell年代、のためにこれを使用して考えた

...など、すべての機能を備えた標準KVOを使用して観察よりそんなに簡単に思えます。私は、保持サイクルや何かがあるとは思わないが、私はそれらを見つけ出すことでそれほど良くはない。

私はこのメソッドを私のアプリケーションに適用する前にいくつかの長所と短所を得ることを望んでいたそれが世界で最も愚かな考えであることを知るために。しかし私にはそれは大丈夫だと思われる。

+2

KVOと比較して最大の欠点は、全く細かいことではありません(自分のニーズに合っているかもしれません)。モデルに複数のプロパティと1つの "updateBlock"がある場合、実際に何が更新されたのか分かりません。何かが更新されただけです。 – rmaddy

答えて

2

私はRxSwiftの学習が良い考えだと思います。しかし、その間に、あなたがやっていることは、大部分がうまくいきます。このアプローチの限界は、コールバックが1つだけに制限されていることです。 RxSwiftはObservableに任意の数のサブスクリプションを許可します。私はこの回答がかなり意見に基づいていることを前もって謝罪します。

私は、パラメータとして「観察」の値を持つようにupdateBlockを変更するだろう、すなわちサイクルを維持回避するのに役立ち、そしておそらく値が変更された、より正確を反映するためにupdateBlockの名前を変更することができ、このよう

var updateBlock: ((String) ->())? 

すなわち、

var awesomeTextUpdate: ((String) ->())? 

しかし、@rmaddyは正しいですが、これはあなたが観察したいかもしれない複数の特性を持つ痛みになります。これは、列挙型のプロパティとその値で部分的に解決できます。

class AwesomeViewModel { 
    enum Property { 
    case awesomeText(String) 
    case awesomeNumber(Int) 
    } 
} 

単にswitchProperty列挙上のクライアントそして

var awesomeText: String { 
    didSet { 
    updateBlock?(.awesomeText(awesomeText)) 
    } 
} 

からupdateBlockタイプを持っている

var updateBlock: ((AwesomeViewModel.Property) ->())? 

didSetができ変えます。彼らが気にしない場所で休憩し、どこにいるかにアクセスしてください。潜在的に観測可能なプロパティが多数ある場合、これは苦痛になることがありますが、クライアントは特定のケースでは1つしか必要としません。

正しい妥協策がないように思えば、RxSwiftがより良い長期的な解決策である可能性があることが主な原因です。ただし、このパラダイムを広く複製することができない場合は、オプションの機能は問題ありません。忘れないでください:あなた自身を繰り返さないでください。

tl;あなたがしていることは妥当だと思われますが、うまく調整できません。

+0

すばらしい答え!ありがとうございました。うん、ポイント@rmaddyが本当に私に当たった。私が4つの変数を更新した場合、UIは3つの不必要な時間を更新します。それは許容できません。私は今、すべてのViewModelに余分な変数を保持することを考えています。例えば、 "needsSet"このboolが 'true'に設定されている場合はupdateBlockを呼び出します。変数を更新するたびに、このブール値を 'true'に設定する必要があり、ブロックが呼び出され、ブロック内でブール値を' false'に戻す必要があります。不必要なUI更新が発生する可能性があり、更新ごとに1回だけです。 – Sti

関連する問題