しめ鯖日記

swift, iPhoneアプリ開発, ruby on rails等のTipsや入門記事書いてます

SwiftBondでViewとViewModelを繋いでみる

SwiftBondを試してみました。

github.com

インストール

CocoaPodsでインストールします。
podには"SwiftBond"でなく"Bond"と入れます。

platform :ios, "8.0"

use_frameworks!

pod "Bond"

ViewとModelを繋いでみます

ViewController, Storyboard, ViewModelを用意します。

Storyboardには下のようにLabelとTextFieldを貼り付けます。

f:id:llcc:20151116225819p:plain

次にViewModelを作ります。

import Foundation
import Bond

class ViewModel {
    var text = Observable<String?>("初期値")
}

最後にViewControllerを作り、その中でLabelとTextFieldをViewModelに紐付けます。

import UIKit

class ViewController: UIViewController {
    @IBOutlet weak var label: UILabel!
    @IBOutlet weak var textField: UITextField!
    
    let viewModel = ViewModel()
    
    override func viewDidLoad() {
        textField.bnd_text.bindTo(viewModel.text) // textFieldの値が変わったらviewModel.textに反映される
        label.bnd_text.bidirectionalBindTo(viewModel.text) // 双方向バインディング、viewModel.textの値が変わった場合にもViewに反映される
    }
}

実際に動かすと、TextFieldの値を変更したらLabelにも反映されるようになりました。

f:id:llcc:20151116230531g:plain

お手軽にTextFieldとLabelを紐付ける

TextFieldとLabelをつなげるだけなら下の書き方でもいけるようです。

// textField.bnd_text.bindTo(viewModel.text) // textFieldの値が変わったらviewModel.textに反映される
// label.bnd_text.bidirectionalBindTo(viewModel.text)
textField.bnd_text ->> label.bnd_text

Labelに値を渡す時に加工する

mapを使えば渡す文字列を加工する事ができます

textField.bnd_text.map { $0! + "!" } ->> label.bnd_text // LabelにはTextFieldの値に!を付けた文字が入る

特定条件の時だけLabelに反映する

filterを

textField.bnd_text.filter { $0?.characters.count < 3 } ->> label.bnd_text // 3文字以上の場合はLabelに値が反映されない

TextFieldの値の変更時イベントを取得する

イベントの取得だけならobserveでできるようです。

textField.bnd_text.observe { text in
    print(text)
}

UITableView

UITableViewとDataSourceは下のように紐付けます。

class ViewController: UIViewController {
    @IBOutlet weak var tableView: UITableView!
    
    override func viewDidLoad() {
        let array1 = ObservableArray(["1つ目", "2つ目", "3つ目"])
        let array2 = ObservableArray(["First", "Second"])
        let dataSource = ObservableArray([array1, array2])
        
        dataSource.bindTo(tableView) { indexPath, dataSource, tableView in
            let cell = tableView.dequeueReusableCellWithIdentifier(
                "Cell", forIndexPath: indexPath)
            let name = dataSource[indexPath.section][indexPath.row]
            cell.textLabel?.text = name
            return cell
        }
    }
}

f:id:llcc:20151116234043p:plain

UITableViewのその他のdataSource

BNDTableViewProxyDataSourceを使う事でSectionHeaderのカスタマイズもできます。
しかしBNDTableViewProxyDataSourceには

class ViewController: UIViewController {
    @IBOutlet weak var tableView: UITableView!
    
    override func viewDidLoad() {
        let array1 = ObservableArray(["1つ目", "2つ目", "3つ目"])
        let array2 = ObservableArray(["First", "Second"])
        let dataSource = ObservableArray([array1, array2])
        
        dataSource.bindTo(tableView, proxyDataSource: self) { indexPath, dataSource, tableView in
            let cell = tableView.dequeueReusableCellWithIdentifier(
                "Cell", forIndexPath: indexPath)
            let name = dataSource[indexPath.section][indexPath.row]
            cell.textLabel?.text = name
            return cell
        }
    }
}

extension ViewController: BNDTableViewProxyDataSource {
    func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return "Header"
    }
}

f:id:llcc:20151116234242p:plain

didSelect等のdelegateメソッド

delegateメソッドは普通にselfを指定するようです。

class ViewController: UIViewController {
    @IBOutlet weak var tableView: UITableView!
    
    override func viewDidLoad() {
        let array1 = ObservableArray(["1つ目", "2つ目", "3つ目"])
        let array2 = ObservableArray(["First", "Second"])
        let dataSource = ObservableArray([array1, array2])
        
        dataSource.bindTo(tableView) { indexPath, dataSource, tableView in
            let cell = tableView.dequeueReusableCellWithIdentifier(
                "Cell", forIndexPath: indexPath)
            let name = dataSource[indexPath.section][indexPath.row]
            cell.textLabel?.text = name
            return cell
        }
        
        tableView.delegate = self
    }
}

extension ViewController: UITableViewDelegate {
    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        print("SELECT!!!")
    }
}

参考URL

Swift bondでつなげてプログラミング - Software
SwiftBondでデータバインドを実現する - 俄