Graphical reactivecocoa basic function

Time:2020-11-1

This article only applies to reactivecocoa v2.5


For functional responsive programming (FRP), you can refer to

  • What is (functional) reactive programming?
  • Specification for a Functional Reactive Programming language

Graphical reactivecocoa basic function

Streams of values over time

The simplest sentence on reactivecocoa repo describes the essence of FRP. Repo itself provides APIs of compositing and transforming streams of values. The abstraction of streams of values in reactivecocoa should be racstream, and composition and transformation is the focus of this paper.

First, explain two basic concepts in reactive cocoa

  • Signal a signal is a steam of values, signals can be transformed, combined, etc
  • A subscriber subscribes to a signal. RAC lets blocks, objects, and properties subscribe to signals

filter

RACSignal *signal = [@[ @1, @2, @3 ] rac_sequence].signal; signal = [signal filter:^BOOL(NSNumber *value) {
    return value.integerValue % 2;
}];
[signal subscribeNext:^(NSNumber *value) {
    NSLog(@"%@", value);
}];

Graphical reactivecocoa basic function

map

  RACSignal *signal = [@[ @1, @2, @3 ] rac_sequence].signal;
  signal = [signal map:^id(NSNumber *value) {
    return @(value.integerValue * 2);
  }];
  [signal subscribeNext:^(NSNumber *value) {
    NSLog(@"%@", value);
  }];

Graphical reactivecocoa basic function

merge

RACSignal *signal1 = [@[ @1, @2 ] rac_sequence].signal;
RACSignal *signal2 = [@[ @4, @5 ] rac_sequence].signal;

[[signal1 merge:signal2] subscribeNext:^(NSNumber *value) {
    NSLog(@"%@", value);
}];

Graphical reactivecocoa basic function

combineLatest

  RACSignal *signal1 = [@[ @1, @2 ] rac_sequence].signal;
  RACSignal *signal2 = [@[ @3, @4 ] rac_sequence].signal;

  [[signal1 combineLatestWith:signal2] subscribeNext:^(RACTuple *value) {
    NSLog(@"%@", value);
  }];

Graphical reactivecocoa basic function

combineLatest & reduce

  RACSignal *signal1 = [@[ @1, @2 ] rac_sequence].signal;
  RACSignal *signal2 = [@[ @3, @4 ] rac_sequence].signal;

  [[[signal1 combineLatestWith:signal2]
      reduceEach:^id(NSNumber *v1, NSNumber *v2) {
        return @(v1.integerValue * v2.integerValue);
      }] subscribeNext:^(RACTuple *value) {
    NSLog(@"%@", value);
  }];

Graphical reactivecocoa basic function

flatten

RACSignal *signal1 = [@[ @1, @2 ] rac_sequence].signal;
RACSignal *signal2 = [RACSignal return:signal1];

[[signal2 flatten] subscribeNext:^(NSNumber *value) {
    NSLog(@"%@", value);
}];

Graphical reactivecocoa basic function

flattenMap

RACSignal *signal = [@[ @1, @2 ] rac_sequence].signal;

[[signal flattenMap:^RACStream *(NSNumber *value) {
    return [RACSignal return:@(value.integerValue * 2)];
}] subscribeNext:^(NSNumber *value) {
    NSLog(@"%@", value);
}];

Graphical reactivecocoa basic function

not replay

RACSubject *letters = [RACSubject subject];
RACSignal *signal = letters;
[signal subscribeNext:^(id x) {
    NSLog(@"S1: %@", x);
}];
[letters sendNext:@"A"];
[signal subscribeNext:^(id x) {
    NSLog(@"S2: %@", x);
}];
[letters sendNext:@"B"];
[letters sendNext:@"C"];

Graphical reactivecocoa basic function

replay

RACSubject *letters = [RACReplaySubject subject];
RACSignal *signal = letters;
[signal subscribeNext:^(id x) {
  NSLog(@"S1: %@", x);
}];
[letters sendNext:@"A"];
[signal subscribeNext:^(id x) {
  NSLog(@"S2: %@", x);
}];
[letters sendNext:@"B"];
[signal subscribeNext:^(id x) {
  NSLog(@"S3: %@", x);
}];
[letters sendNext:@"C"];

Graphical reactivecocoa basic function

replayLast

RACSubject *letters = [RACSubject subject];
RACSignal *signal = [letters replayLast];
[signal subscribeNext:^(id x) {
  NSLog(@"S1: %@", x);
}];
[letters sendNext:@"A"];
[signal subscribeNext:^(id x) {
  NSLog(@"S2: %@", x);
}];
[letters sendNext:@"B"];
[signal subscribeNext:^(id x) {
  NSLog(@"S3: %@", x);
}];
[letters sendNext:@"C"];

Graphical reactivecocoa basic function

replayLazily

RACSubject *letters = [RACSubject subject];
RACSignal *signal = [letters replayLazily];
[letters sendNext:@"A"];
[signal subscribeNext:^(id x) {
  NSLog(@"S1: %@", x);
}];
[letters sendNext:@"B"];
[signal subscribeNext:^(id x) {
  NSLog(@"S2: %@", x);
}];
[letters sendNext:@"C"];
[signal subscribeNext:^(id x) {
  NSLog(@"S3: %@", x);
}];
[letters sendNext:@"D"];

Graphical reactivecocoa basic function

zip

RACSubject *letters = [RACSubject subject];
RACSubject *numbers = [RACSubject subject];

RACSignal *combined =
    [RACSignal zip:@[ letters, numbers ]
            reduce:^(NSString *letter, NSString *number) {
              return [letter stringByAppendingString:number];
            }];

// Outputs: A1 B2 C3
[combined subscribeNext:^(id x) {
  NSLog(@"%@", x);
}];

[letters sendNext:@"A"];
[letters sendNext:@"B"];
[letters sendNext:@"C"];
[numbers sendNext:@"1"];
[numbers sendNext:@"2"];
[numbers sendNext:@"3"];

Graphical reactivecocoa basic function

Complete source code can be found here demo