ReactiveCocoa 实战
分享 ReactiveCocoa 在实际使用过程中的一些经验,用案例来展示。
假设读者对 ReactiveCocoa 基本概念都比较熟悉,比如 signal,sequence,一些基本的对 signal 的操作等。 不太熟悉的可以阅读 halfrost 作者的系列文章,从源码层面分析,讲解的很全面。
数组操作
数据元素中的 signal
一个 viewModels 数组,任意一个 viewModel number 字段值大于 0,则发送 1,否则 0
参考 https://stackoverflow.com/a/19711002/1911562
声明 ViewModel
@interface ViewModel : NSObject
@property (nonatomic) NSNumber *number;
@end
@implementation ViewModel
@end
@interface ExampleTest : XCTestCase
@property (nonatomic, copy) NSArray *viewModels;
@end
创建信号
@weakify(self)
/// 初始化 signal
/// 每次设置 viewModels 的 signal
///============================
RACSignal *enabled = RACObserve(self, viewModels);
enabled = [enabled map:^id _Nullable(NSArray * _Nullable viewModels) {
/// 这是 sequence,里面的元素是各个 viewModel 的 number 字段返回的 bool 类型 signal,
/// `startWith` 默认开始的 signal 发送的值是 @(NO)
/// 如果不设置默认的 signal,在 viewModels 为空时是不会发送任何东西,因为是 `emptySignal` 会直接 completed
RACSequence *inputSignals = [[viewModels.rac_sequence map:^id _Nullable(ViewModel * _Nullable viewModel) {
/// RACObserve() 对 self 有引用
@strongify(self)
return [RACObserve(viewModel, number) map:^id _Nullable(id _Nullable number) {
return @([number integerValue] > 0);
}];
}] startWith:[RACSignal return:@(NO)]];
/// 任意一个 viewModel 修改,都需要发送值,而且需要合并其他 viewModel 最新的值
/// 所以需要用 `combineLatest`
/// 对 viewModels signal sequence 进行合并成一个 signal
/// 合并的 signal 发送的值是形如 (0,1) 的 tuple
RACSignal *ret = [RACSignal combineLatest:inputSignals];
/// 对 tuple 进行 or 操作
/// (0,1) => 0
return [ret or];
}];
/// 因为每次设置 viewModels 都会返回一个 signal,我们要切换到最新的一个
/// 这里转换之前的 enabled 是高阶信号(信号里面元素是信号)
enabled = [enabled switchToLatest];
测试
/// 测试
///=========================
ViewModel *vm1 = [ViewModel new];
ViewModel *vm2 = [ViewModel new];
self.viewModels = @[vm1, vm2];
/// 初始化两个 vm
[[enabled subscribeNext:^(id _Nullable x) {
NSLog(@"sub-1 %@", x);
XCTAssert([x isEqual:@(NO)]);
}] dispose];
/// 设置其中一个 vm 的值
vm2.number = @2;
[[enabled subscribeNext:^(id _Nullable x) {
NSLog(@"sub-2 %@", x);
XCTAssert([x isEqual:@(YES)]);
}] dispose];
/// 清空
vm2.number = nil;
[[enabled subscribeNext:^(id _Nullable x) {
NSLog(@"sub-3 %@", x);
XCTAssert([x isEqual:@(NO)]);
}] dispose];
/// 设置两个 vm 的值
vm1.number = @1;
vm2.number = @2;
[[enabled subscribeNext:^(id _Nullable x) {
NSLog(@"sub-4 %@", x);
XCTAssert([x isEqual:@(YES)]);
}] dispose];
结果
Test Case '-[ExampleTest testViewModelsOnePropertyObservation]' started.
2019-09-23 13:05:14.958947+0800 ReactiveCocoaDemo[21180:1246792] sub-1 0
2019-09-23 13:05:14.961012+0800 ReactiveCocoaDemo[21180:1246792] sub-2 1
2019-09-23 13:05:14.963358+0800 ReactiveCocoaDemo[21180:1246792] sub-3 0
2019-09-23 13:05:14.965047+0800 ReactiveCocoaDemo[21180:1246792] sub-4 1
可以看到,初始化的时候发送 0
,是因为手动在最前面拼接了 [RACSignal return:@(NO)]
信号。