【Swift】Try! ReactiveCocoa


これはメモです

私もまだ良くわかってません。^^;
指摘やツッコミあればお願いします。
書く価値ないとかは、おやめてください。m(__)m

ReactiveCocoaとは?

Swift,Objective-CでFRP(ファンクショナル・リアクティブ・プログラミング)を行うためのライブラリー
証言1:コードが短くなります。
証言2:状態の保持がなくなります。
証言3:if文とかほとんど書かなくなった。
証言4:リトライ処理とか楽になった。
証言5:MVVMとかに欠かせない。
証言6:プログラミングが楽しくなった。
略称:RAC 巷では「ラック」と呼ぶ人が多い気がする。
https://github.com/ReactiveCocoa/ReactiveCocoa

RxSwiftとの違いは?

RACはHot,Coldのオブジェクトが明確に分かれてて良い。
RxSwiftはHot,Coldが別れてなく1オブジェクトで場合によって変化するらしい。

RxはAndroidなど色々なプラットフォームでもライブラリーを提供しているので、他のプラットフォームで入りやすいのかも?
RACはObjective-C,Swiftオンリー

Github Star数(2016/7/2現在)

RAC -> 14500
RxSwift -> 5200

ReactiveCocoaインストール

基本PodかCarthageでインストールします。
色々方法ありますが、Carthageを使ってやります!

HomeBrewインストール

CarthageをインストールするにはHomeBrewが必要です。
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
brew doctor

EL ChaptanからBrewコマンドが通らない可能性もあります。(ハマった・・・)

HomeBrewとは?

HomeBrewでCarthageインストール

brew update
brew install carthage

CarthageでReactiveCocoaをプロジェクトに導入

vim Cartfile(プロジェクトディレクトリにて)
github "ReactiveCocoa/ReactiveCocoa"(Vimエディタにて wqで保存)
carthage update --platform iOS(tvOS,macOSとかあるのでiOSだけに絞る)

完了しFinderを見ると下記のようなフォルダー構成になってます。
ReactiveCocoa.frameworkResult.frameworkが作成されているのを確認してください。

  1. プロジェクトへ戻り、プロジェクト(左上,TryReactiveCocoa)をタップしてください。
  2. Build Phasesタブをタップ
  3. +ボタンで先ほどのライブラリー(ReactiveCocoa,Result)を「Add Other...」(ダイアログの左下)から選択してください。
  4. +ボタンで「New Run Script Phase」を選択してください。
  5. Run Scriptという項目が増えたと思いますので下記の文字を入力してください。

/usr/local/bin/carthage copy-frameworks
$(SRCROOT)/Carthage/Build/iOS/Result.framework
$(SRCROOT)/Carthage/Build/iOS/ReactiveCocoa.framework


これでReactiveCocoaが使えるようになりました!

ReactiveCocoaデモ

LabelとTextFiledを用意して、Textfileldに小文字が入力されるとLabelに大文字がリアルタイムに変換されて表示されるデモを行います。(在り来りですいません...)
値の変化をViewに結合させる事をBindingと言うらしい。

ViewController.swift

import UIKit
import ReactiveCocoa
import Result

class ViewController: UIViewController {

    @IBOutlet weak var label: UILabel!
    @IBOutlet weak var textfield: UITextField!

    let (updateTextSignal, updateTextObserver) = SignalProducer<String, NoError>.buffer(0)

    override func viewDidLoad() {
        super.viewDidLoad()

        updateTextSignal
            .map { (text) -> String in
                return text.uppercaseString
        }
            .startWithNext { [weak self] (text) in
            self?.label.text = text
        }

        textfield.addTarget(self, action: #selector(updateText(_:)), forControlEvents: .EditingChanged)

    }

    func updateText(sender: UITextField) {
        print(sender.text)
        updateTextObserver.sendNext(sender.text!)
    }
}

Signal + Observer = Stream

Stream

stream は良く「川」と例えられます。
stream はこの場合「String」が流れてくる「川」だと思ってください。

下記にて steamを作成してます。
SignalProducer<Hoge,Error>の部分で「川に流したい型」と「Errorの型」を書きます。
今回は文字列のStringとエラー無しの意味のNoErrorです。

let (updateTextSignal, updateTextObserver) = SignalProducer<String, NoError>.buffer(0)

Observer

この「川」にStringを投げ込むのがupdateTextObserverです。
sendNextの部分でTextFiledに入力された文字を川に投げてます。

updateTextObserver.sendNext(sender.text!)

Signal

Observerが投げたStringを受け取るためにはupdateTextSignalstartWithNextで受け取ります。
引数がクロージャーになっていてClosureの引数にTextFieldに入力されたStringが入ってきます。

updateTextSignal.startWithNext { [weak self] (text) in
    self?.label.text = text
}

[weak self]は循環参照のメモリリーク対策です。

Operator

途中に記述されている.mapがStringを変換するメソッドになります。
このmapをOperatorと呼びます。
map{}の中でStringを加工してreturnしてあげます。
Operatorには色々と種類がありRAC-marblesでどのような動作をするのかを確認できます。

updateTextSignal
    .map { (text) -> String in
        return text.uppercaseString
}
    .startWithNext { [weak self] (text) in
    self?.label.text = text
}

以上です。

まとめ

初心者の方(私も含め)は動作環境を整えるだけでも一苦労ではないでしょうか?
なので、なるべくスクショで説明してみました。
で、結局ReactiveCocoaは何がいいのか!?それは言わないでください。
他のも言いたいことは沢山ありますが、ややこしくなるのでこの辺で!m(__)m

以上、Try! ReactiveCocoaでした。

サンプルコード