逆引きReactiveCocoa: @YES/@NOをトグルで送るRACCommandを用意する

元ネタ: Command which sends alternating YES/NO values · Issue #767 · ReactiveCocoa/ReactiveCocoa


ボタン・ジェスチャーなどのUI操作とRACSignalを仲介するクラスとしてRACCommandがあります。これを用いて、状態(フラグとなるインスタンス変数/プロパティ)を持たずにトグルボタンを表現するパターンです。

// ブロックの戻り値が`[command execute:senderOrValue]`の戻り値となる。
RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^(id _) {
    return [RACSignal return:RACUnit.defaultUnit];
}];

RACSignal *alternating = [[[command.executionSignals // `-execute:`の度にその戻り値のシグナルを送るシグナル。
    flatten]
    startWith:RACUnit.defaultUnit] // ユーザー操作前に初期値がセットされるようにする。
    scanWithStart:@NO combine:^(NSNumber *previous, id _) {
        // 前回の値を反転したブール値を返し、
        // コマンドの実行によって得られた値は無視する(_ == RACUnit.defaultUnit)。
        //
        // 最初に`@NO`を反転するため、シグナルの初回の値は`@YES`となる。
        return @(!previous.boolValue);
    }];
RAC(self, onOff) = alternating;

// `UIControlEventTouchUpInside`のイベントで`-execute:`される。
button.rac_command = command;