简介:

RAC 指的就是 RactiveCocoa ,是 Github 的一个开源框架,能够帮我们提供大量方便的事件处理方案,让我们更简单粗暴地去处理事件,现在分为 ReactiveObjCReactiveSwift ,两个框架的功能使用相似.

RAC 的核心思想:创建信号 - 订阅信号 - 发送信号.

Podfile文件:

 platform :ios, '10.0'
target "RAC" do
pod 'ReactiveObjC', '~> 3.1.0'
use_frameworks!
end

1. RACSignal 信号(主线程中执行)

 //    创建信号
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
// 发送信号
[subscriber sendNext:@"发送信号"];
return nil;
}]; /* 订阅信号 */
RACDisposable *disposable = [signal subscribeNext:^(id _Nullable x) { NSLog(@"信号内容:%@", x);
}]; // 取消订阅
[disposable dispose];

结果:


2. RACSubject 信号(主线程中执行)

通常用来代替代理,有了它,就不必要定义代理了。

 //    创建信号
RACSubject *subject = [RACSubject subject];
// 订阅信号(通常在别的视图控制器中订阅,与代理的用法类似
[subject subscribeNext:^(id _Nullable x) {
NSLog(@"信号内容:%@", x);
}];
[subject subscribeNext:^(id _Nullable x) {
// block调用时刻:当信号发出新值,就会调用.
 NSLog(@"第二个订阅者%@",x);
}];
// 发送信号
[subject sendNext:@"发送信号"];

结果:


3. RACTuple 元组(主线程中执行)

RAC 的元祖,跟我们 OC 的数组其实是一样的,它其实就是封装了我们 OC 的数组。

3.1

 //    把值包装成 元组
RACTuple * tuple = RACTuplePack(@"abc",@"def",@"ghj");
// 解析元组
// RACTupleUnpack(NSString * a , NSString * b , NSString * c) = tuple ;
NSLog(@"RACTuple 元组包装: pack = %@ ",tuple);

结果:

3.2 NSDictionary 元组 , 将字典里面的每一对 keyValue 列举出来(开了一个新的线程,异步列举)

     NSDictionary * dicTuple = @{@"name":@"Jakey" , @"age":@ , @"student":@(YES)};
[dicTuple.rac_sequence.signal subscribeNext:^(id _Nullable x) {
NSString * key = [(RACTuple *)x objectAtIndex:];
id value = [(RACTuple *)x objectAtIndex:];
NSLog(@"NSDictionary 元组使用 = %@ , key = %@ , value = %@ , thread = %@",x,key,value,[NSThread currentThread]);
}completed:^{
NSLog(@"NSDictionary 元组使用 completed , thread = %@",[NSThread currentThread]);
} ];

结果:

3.3 NSArray 元组 ,将数组内的所有数据列举出来 (异步列举)

  NSArray * array = @[@"klr",@"nop",@"rst"];
[array.rac_sequence.signal subscribeNext:^(id _Nullable x) {
NSLog(@"NSArray 元组 x = %@ , thread = %@",x,[NSThread currentThread]);
}error:^(NSError * _Nullable error) {
NSLog(@"NSArray 元组 error = %@",error);
} completed:^{
NSLog(@"NSArray 元组 completed ,thread = %@",[NSThread currentThread]);
}];

结果:

3.4 异步列出 数组 或 字典 内容

     NSArray * array = @[@"重装炮台111111111",@"追击潜能222222222222",@"警戒地雷333333333"];
NSArray * mapArray = [[array.rac_sequence map:^id _Nullable(id _Nullable value) {
NSLog(@"value = %@ , thread = %@",value,[NSThread currentThread]);
return [value stringByAppendingString:@" temp"];
}] array] ;
NSLog(@"===== %@", mapArray);

结果:


4. RACReplaySubject 先发送 再订阅(主线程中执行)

先发送 再订阅 (这个比较 实用 ,可以在不知道什么时候发送信号的情况下准确的接收到信号)(主线程中执行)

 //    Capacity 事先预指订阅的个数,里面是动太数组
RACReplaySubject * replaySubject = [RACReplaySubject replaySubjectWithCapacity:]; // 发送
[replaySubject sendNext:@"RACReplaySubjectDome 先发送 1"];
[replaySubject sendNext:@"RACReplaySubjectDome 先发送 2"];
[replaySubject sendCompleted]; // 订阅
[replaySubject subscribeNext:^(id _Nullable x) {
NSLog(@"subscribeNext:x = %@ error completed , thread = %@",x,[NSThread currentThread]);
} error:^(NSError * _Nullable error) {
NSLog(@"error = %@ , thread = %@",error,[NSThread currentThread]);
} completed:^{
NSLog(@"completed ! , thread = %@",[NSThread currentThread]);
}]; // 延时订阅,一样可以接收到信号
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[replaySubject subscribeNext:^(id _Nullable x) { NSLog(@"subscribeNext: x = %@, thread = %@",x,[NSThread currentThread]);
}];
});

结果:


5. RACMulticastConnection :广播连接(将 RACSignal 转成 RACMulticastConnection , block 在 main 主线程执行)

 //  网络数据加载方法
-(void)loadDataFromNetwork:(void(^)(NSArray * dataArr))resultBlock
{
NSLog(@"loadDataFromNetwork selector thread = %@",[NSThread currentThread]); resultBlock(@[@"temp = 1" , @"temp = 2" , @"temp = 3"]);
} - (RACSignal *)returnSignal {
// 不能解决 _view ( === self->_view , 这样就无法解决强引用的问题)
// __weak typeof(self) weakSelf = self ; // 无论哪种用法都可以解决强引用问题
@weakify(self); RACSignal * signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
// @weakify(self) 配套使用
@strongify(self);
NSLog(@"connection createSignal , thread = %@",[NSThread currentThread]); [self loadDataFromNetwork:^(NSArray *dataArr) {
NSLog(@"loadDataFromNetwork block dataArr = %@ , thread = %@",dataArr , [NSThread currentThread]);
// 发送信号
[subscriber sendNext:dataArr];
[subscriber sendCompleted]; //信号发送结束
}]; return [RACDisposable disposableWithBlock:^{
NSLog(@"connection disposableWithBlock ,thread = %@",[NSThread currentThread]);
}];
}]; return signal;
}

5.1 直接订阅

 //    直接订阅

     RACSignal * signal = [self returnSignal];
[signal subscribeNext:^(id _Nullable x) { NSLog(@"subscribeNext x = %@ , thread = %@",x,[NSThread currentThread]); }];

打印结果:

5.2 Signal 抓化为:Connection

 //    将 signal 转化成 connection
RACMulticastConnection * connection = [signal publish]; // 订阅信号
// RACSubject:RACSubscriber
[connection.signal subscribeNext:^(id _Nullable x) { NSLog(@"链接One x = %@ , thread = %@",x,[NSThread currentThread]);
}];
[connection.signal subscribeNext:^(id _Nullable x) { NSLog(@"链接Two x = %@ , thread = %@",x,[NSThread currentThread]);
}]; // 连接
// RACSubject 订阅 RACSignal
[connection connect];

打印结果:

 6. RACCommand:处理事件的操作.(主线程中执行)

(1) RACCommand : 内部必须返回 RACSignal

(2) executionSignals : 信号外的信号

  (2.1) switchToLatest 最新发出来信号的 RACSignal 类型

  (2.2) 能过 (2.1)的诠释,那么只要用 switchToLatest subscribeNext: 订阅,就可以接收到发出来的信号

(3) 下面是执行的顺序,用 (index)表示

(4) execute:(id)input ; 该对象方法必须被调用(调用次数只有一次有效)才会执行一些相关操作,所有的 block 执行操作的 入口

     RACCommand * command = [[RACCommand alloc] initWithSignalBlock:^RACSignal * _Nonnull(id  _Nullable input) {
// input 即是执行 execute:(id)input; 传进来的值 (3)
NSLog(@"init RACCommand block 被执行 initWithSignalBlock input = %@ , thread = %@",input,[NSThread currentThread]); return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
// (6)
NSLog(@"内部创建的信号block 被执行 createSignal , thread = %@",[NSThread currentThread]); // 发送信号
[subscriber sendNext:@"create Signal for somthing %@"];
[subscriber sendCompleted]; return [RACDisposable disposableWithBlock:^{
// 当 [subscriber sendCompleted] 调用时就会执行释放功能的 block (8)
NSLog(@"内部信号被释放 disposableWithBlock , thread = %@",[NSThread currentThread]);
}]; }];
}]; // 订阅最新发出来信号的 signal (7)
[command.executionSignals.switchToLatest subscribeNext:^(id _Nullable x) { NSLog(@"执行最近的 signal , x = %@ , thread = %@",x,[NSThread currentThread]);
}]; // executionSignals 这里传的 x 值类型为 RACDynamicSignal 类型对象 (5)
[command.executionSignals subscribeNext:^(id _Nullable x) { NSLog(@"executionSignals subscribeNext x = %@ , thread = %@",x,[NSThread currentThread]);
}]; // 查看将要执行,每执行完一个步聚 都会调用一次查看哪个 signal block(即 第 x 个 block ) 将被使用 (2)(4)(9)
// signal 的 skip: 方法功能是跳过 skipCount 个 使用 block 的查看
[[[command executing] skip:] subscribeNext:^(NSNumber * _Nullable x) {
NSLog(@"executing signal subscribeNext x = %@ , thread = %@",x,[NSThread currentThread]);
}]; // 只执行一次 (1)
[command execute:@"我要执行啦*****"];

打印结果:


7.NSObject 分类中 rac_liftSelector… 方法的使用(即等待成所有的 RACSignal 对象发送完信号再执行方法) (主程中执行)

     RACSignal * signalOne = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {

         // 现在想发出信号了
[subscriber sendNext:@"网络请求数据 1"]; // 不需要释放操作
return nil ;
}]; RACSignal * signalTwo = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) { // 现在想发出信号了
[subscriber sendNext:@"网络请求数据 2"]; // 不需要释放操作
return nil ;
}]; [self rac_liftSelector:@selector(updateUIWithSignalOneMessage:signalTwoMessage:) withSignalsFromArray:@[signalOne , signalTwo]]; // 当所有数据都拿到手后更新UI , 传的数据就是 signalOne 和 signalTwo 发出来的信号数据 ,(所以当前设计的接收方法 也必需要有两个参数,发出的信号按顺序 传参)
// 假如当前对象方法只设计 传一个参数,那么就会导致崩溃
-(void)updateUIWithSignalOneMessage:(id)signalOneMessage signalTwoMessage:(id)signalTwoMessage
{
NSLog(@"signalOneMessage = %@ , signalTwoMessage = %@ , thread = %@",signalOneMessage,signalTwoMessage,[NSThread currentThread]);
}

打印结果:


8. NSNotificationCenter : 使用了 RAC 把监听通知的方法改成了 block 形式

 // 监听通知
[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardDidHideNotification object:nil] subscribeNext:^(NSNotification * _Nullable x) {
NSLog(@"NSNotification 1 x = %@",x.userInfo);
}]; [[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardDidHideNotification object:nil] subscribeNext:^(NSNotification * _Nullable x) {
NSLog(@"NSNotification 2 x = %@",x.userInfo);
}]; // 发出通知
[[NSNotificationCenter defaultCenter] postNotificationName:UIKeyboardDidHideNotification object:nil];

打印结果:


9. RAC UITextField 监听 text 变化

     // UITextField RAC使用
UITextField * textField = [[UITextField alloc] initWithFrame:CGRectMake(, , , )];
textField.backgroundColor = [UIColor redColor];
[self.view addSubview:textField]; [[textField rac_textSignal] subscribeNext:^(NSString * _Nullable x) {
NSLog(@"text = %@ , textField.text = %@ , thread = %@",x,textField.text,[NSThread currentThread]);
}]; // 绑定 lable.text
UILabel * lable = [[UILabel alloc] initWithFrame:CGRectMake(, , , )];
lable.backgroundColor = [UIColor greenColor];
[self.view addSubview:lable]; // 绑定 lable.text 永远等于 textField.text
RAC(lable,text) = textField.rac_textSignal ;

输入为: China Welcome

打印结果:


10. RAC KVO 监听属性内容变化

     [RACObserve(self, age) subscribeNext:^(id  _Nullable x) {

         NSLog(@"KVO 监听到 age 内容发生变化 ,变为 %@ , thread = %@",x,[NSThread currentThread]);
}]; -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
self.age++ ;
}

打印结果:


11. RACSignal 的 bind 绑定

bind 里面的做法:

(1) 创建一个 RACSignal 对象做为 bind 方法的返值;

(2) 当我们拿到该返的 RACSignal 类对象 tempSignal 去进行订阅;

(3) 然后会执行创建 RACSignal 对象时的 block A (RACSignalBindBlock),并在里面执行 bindBlock 拿到 返回的 block B (RACSignal)(返回值为 RACSignal 对象);

(4) 再执行 block B 就拿到 RACReturnSignal 对象;

(5) RACReturnSignal 对象 进行订阅,然后在该订阅 block 里面拿到 value 值;

(6) tempSignal 的 subscriber 订阅者 发送信号值 value , 最后在外面 tempSignal 对象的订阅就接收到信息了。

     UITextField * textField = [[UITextField alloc] initWithFrame:CGRectMake(, , , )];
textField.backgroundColor = [UIColor yellowColor];
[self.view addSubview:textField]; [[textField.rac_textSignal bind:^RACSignalBindBlock _Nonnull{ NSLog(@"绑定 block"); return ^RACSignal * (id _Nullable value, BOOL *stop){ NSLog(@"返回block的值为 = %@",value); return [RACReturnSignal return:value];
}; }] subscribeNext:^(id _Nullable x) {
NSLog(@"signal subscribeNext x = %@",x);
}];

打印结果:


12. RACReplaySubject 对象的 then: 方法

then 功能:可以使 RACSignal 及其子类的 对象有序接收信号

     // 在这里尽量使用 RACReplaySubject 类 ,因为 RACReplaySubject 可以先发送信号,订阅代码可以放在之后写。
// 如果 使用 RACSignal 或 RACSubject ,那么必须要等这些对象订阅完后,发送的信号才能接收的到
RACReplaySubject * subjectA = [RACReplaySubject subject]; // 这就是好处,先发送
[subjectA sendNext:@"AA"];
// 必须要调用这个方法才会来到 then 后的 block
[subjectA sendCompleted]; // 按指定的顺序接收到信号
[[[subjectA then:^RACSignal * _Nonnull{ // 当 subjectA 发送信号完成后 才执行 当前的 block
RACReplaySubject * subjectB = [RACReplaySubject subject]; // 可以单独调用发送信号完成的方法就可以接着执行下一个 then
[subjectB sendCompleted]; return subjectB ; }] then:^RACSignal * _Nonnull{ // 当 subjectB 发送信号完成后 才执行 当前的 block
RACReplaySubject * subjectC = [RACReplaySubject subject]; // subjectC 发送信号
[subjectC sendNext:@"CC"]; return subjectC ; }] subscribeNext:^(id _Nullable x) { // 这个就 "相当于" 订阅了 subjectC 对象(但真正的对象则不是 subjectC 对象) ,x = @"CC"
NSLog(@"RACReplaySubject C x = %@",x);
}];

打印结果:


13. 合并两个及以上 RACSignal 或 RACSignal 的子类对象,用新创建的 RACSignal 对象接收多个 RACSignal 或 RACSignal 的子类对象 发出的信号

 RACReplaySubject * subjectA = [RACReplaySubject subject];
RACReplaySubject * subjectB = [RACReplaySubject subject];
RACReplaySubject * subjectC = [RACReplaySubject subject]; // 三个对象发送信号(只需其中一个或多个发送信号时,合并的 信号对象 都可以在订阅的 block 接收到信息)
[subjectB sendNext:@"BB"];
[subjectA sendNext:@"AA"];
[subjectC sendNext:@"CC"]; // 合并两个信号对象变成一个接收信号对象 subjectD , subjectD 订阅 接收 subjectB 和 subjectA 发送的信号
[[[subjectA merge:subjectB] merge:subjectC] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}]; 

打印结果:


14. 压缩两个及以上 RACSignal 或 RACSignal 的子类对象,用新创建的 RACSignal 对象同时接收多个 RACSignal 或 RACSignal 的子类对象 发出的信号

     RACReplaySubject * subjectA = [RACReplaySubject subject];
RACReplaySubject * subjectB = [RACReplaySubject subject];
RACReplaySubject * subjectC = [RACReplaySubject subject]; // 三个对象同时发送信号,缺一不可
[subjectA sendNext:@"信号AA"];
[subjectB sendNext:@"信号BB"];
[subjectC sendNext:@"信号CC"]; // 合并两个信号对象变成一个接收信号对象 subjectD , subjectD 订阅 接收 subjectB 和 subjectA 发送的信号
// x 类型为 元组 RACTwoTuple 类型:解析使用
[[[subjectA zipWith:subjectB] zipWith:subjectC] subscribeNext:^(id _Nullable x) {
// 注意:元组需要 一层一层 地解析
RACTupleUnpack(RACTuple * AB , NSString * C) = x ;
NSLog(@"x的值为:%@",x); RACTupleUnpack(NSString * A , NSString * B) = AB ;
NSLog(@"AB的值为:%@",AB); NSLog(@"A = %@ , B = %@ , C = %@",A , B , C);
}];

打印结果:


15. 合并两个及以上 RACSignal 或 RACSignal 的子类对象,用新创建的 RACSignal 对象 同时接收多个 RACSignal 或 RACSignal 的子类对象 发出的信号

公共的代码:

 RACReplaySubject * subjectA = [RACReplaySubject subject];
RACReplaySubject * subjectB = [RACReplaySubject subject];
RACReplaySubject * subjectC = [RACReplaySubject subject]; // 三个对象同时发送信号,缺一不可
[subjectA sendNext:@"邮件AA"];
[subjectB sendNext:@"邮件BB"];
[subjectC sendNext:@"邮件CC"];

方法一:

     //也可以把那些信号传的参数聚合成一个值
// 遵守 NSFastEnumeration 协议的类都可成为数组
// reduce block 参数可以自己根据信号设置
[[RACSignal combineLatest:@[subjectA,subjectB,subjectC] reduce:^id (NSString * signalA,NSString * signalB,NSString * signalC){ // 把这 三个中任意 一个发出的信号值 聚合成一个值 NSString 类型 return [NSString stringWithFormat:@"A = %@ , B = %@ , C = %@",signalA , signalB , signalC]; }] subscribeNext:^(id _Nullable x) {
NSLog(@"聚合后三个值变成一个 NSString 类型的值: %@",x);
}];

打印结果:

方法二:

 //    也可以用聚合绑定做法
UILabel * lable = [[UILabel alloc] initWithFrame:CGRectMake(, , , )];
[self.view addSubview:lable];
lable.backgroundColor = [UIColor redColor];
RAC(lable , text) = [RACSignal combineLatest:@[subjectA,subjectB,subjectC] reduce:^id (NSString * signalA,NSString * signalB,NSString * signalC){ // 把这 三个中任意 一个发出的信号值 聚合成一个值 NSString 类型 return [NSString stringWithFormat:@"A = %@ , B = %@ , C = %@",signalA , signalB , signalC]; }]; NSLog(@"lable.text = %@",lable.text);

打印结果:


16. RACSignal 的 map 拦截信号发出的信号和处理数据

     RACReplaySubject * signal = [RACReplaySubject subject];

     [[signal map:^id _Nullable(id  _Nullable value) {
return [NSString stringWithFormat:@"%@ (拦截发出的信号,拼接个想要的东西)",value];
}] subscribeNext:^(id _Nullable x) {
NSLog(@"接收到处理后的信息 = %@",x);
}]; [signal sendNext:@"@(当前信号的信息是Welcome Orange World)"];

结果:


17. 信号中的信号,RACSignal 的 flattenMap 对象方法,用来接收信号对象value 和 信号对象value发出的信息

 RACReplaySubject * signal = [RACReplaySubject subject];
RACSubject * subject = [RACSubject subject]; [[signal flattenMap:^__kindof RACSignal * _Nullable(id _Nullable value) { // value 是信号对象 == subject return [value map:^id _Nullable(id _Nullable value) { return [NSString stringWithFormat:@"(添加拦截信号处理信号) (%@)",value];
}];
}] subscribeNext:^(id _Nullable x) {
NSLog(@"接收到处理后的信息 = %@",x);
}]; [signal sendNext:subject]; [subject sendNext:@" subject 发出信号了"];

结果:


18. 信号过滤器:RACSignal 的 filter: 方法,用来设置一个条件发出的信号才会被接收到

 RACReplaySubject * replaySubject = [RACReplaySubject replaySubjectWithCapacity:];

     // filter block 是一个过滤器,只有满足条件发出的信号才会被接收到
[[replaySubject filter:^BOOL(id _Nullable value) { return ((NSString *)value).length >= ; }] subscribeNext:^(id _Nullable x) { NSLog(@"接收到信号 = %@",x);
}]; // // 发出的信号长度为 5 时,订阅收不到信号信息
// [replaySubject sendNext:@"12345"]; // 发出的信号长度为 >= 6 时,订阅收到信号了信息
[replaySubject sendNext:@""];

结果:


19.RACSignal 信号对象 与 定时器的关系

公用变量:

 // 定时器
// TimeInterval : 间隔时间,秒
// repeats : 是否重复
// blokc : 调用代码块 (在主线程中执行)
if (@available(iOS 10.0, *)) {
[NSTimer scheduledTimerWithTimeInterval: repeats:NO block:^(NSTimer * _Nonnull timer) {
NSLog(@"每隔一秒调用一次当前 block , thread = %@",[NSThread currentThread]);
}];
} else {
}

方法一:

 // RACSignal 制定定时器
// interval : 间隔的时间,秒
/**
onScheduler : 多线程 , 队列
mainThreadScheduler : 主线程中 执行订阅代码块
currentScheduler : 在当前创建时的线程中 执行订阅代码块
*/
/**
schedulerWithPriority: 或 schedulerWithPriority:name: 优先级 , name 表示线程名
// 优先级高,开起 新的线程
RACSchedulerPriorityHigh = DISPATCH_QUEUE_PRIORITY_HIGH,
// 默认优先级,开起 新的线程
RACSchedulerPriorityDefault = DISPATCH_QUEUE_PRIORITY_DEFAULT,
// 优先级低,开起 新的线程
RACSchedulerPriorityLow = DISPATCH_QUEUE_PRIORITY_LOW,
// app 进入后台也可以调用,开起 新的线程
RACSchedulerPriorityBackground = DISPATCH_QUEUE_PRIORITY_BACKGROUND,
*/ [[RACReplaySubject interval: onScheduler:[RACScheduler schedulerWithPriority:RACSchedulerPriorityLow]] subscribeNext:^(NSDate * _Nullable x) {
// x 是当前的时间
NSLog(@"每隔一秒调用订阅代码:x = %@ , 在线程 thread = %@",x,[NSThread currentThread]);
}];

打印结果:

方法二:

     [NSTimer scheduledTimerWithTimeInterval: repeats:NO block:^(NSTimer * _Nonnull timer) {
NSLog(@"每隔一秒调用一次当前 block , thread = %@",[NSThread currentThread]);
}]; [[[RACReplaySubject createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) { [subscriber sendNext:@"~~2秒后调用订阅 block"]; return nil ;
}] delay:] // 延时 5秒 再
subscribeNext:^(id _Nullable x) { NSLog(@"-------------%@",x);
}];

结果:

ReactiveObjC的更多相关文章

  1. ReactiveObjC使用

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 20.0px Menlo; color: #78492a; background-color: #fffff ...

  2. 函数响应式编程及ReactiveObjC学习笔记 (-)

    最近无意间看到一个视频讲的ReactiveObjC, 觉得挺好用的 但听完后只是了解个大概. 在网上找了些文章, 有的写的比较易懂但看完还是没觉得自己能比较好的使用RAC, 有的甚至让我看不下去 这两 ...

  3. 函数响应式编程及ReactiveObjC学习笔记 (二)

    之前我们初步认识了RAC的设计思路跟实现方式, 现在我们再来看看如果使用它以及它能帮我们做什么 One of the major advantages of RAC is that it provid ...

  4. 函数响应式编程及ReactiveObjC学习笔记 (三)

    之前讲了RAC如何帮我们实现KVO / 代理 / 事件 / 通知 今天先不去分析它的核心代码, 我们先看看ReactiveObjC库里面一些特别的东西,  如果大家点开ReactiveObjC目录应该 ...

  5. ReactiveObjC框架的简单介绍

    最近在一直在学习RAC框架的Object-C版本ReactiveObjC(Swift版本为ReactiveSwift),这篇文章简单展示一下学习的成果!!!如果有什么地方理解错误,欢迎大家指正!!!互 ...

  6. iOS 使用cocoapods导入ReactiveCocoa和ReactiveObjC框架

    cocoapods使用 ReactiveObjC -- 对应的是RAC的OC版本,最新3.1.0版本. ReactiveCocoa--对应的是RAC的swift版本,最新7.1.0版本. 1.纯OC项 ...

  7. 【原】导入framework报错解决(以ReactiveObjC.framework为例)

    1.当导入ReactiveObjC.framework后,进行编译时报错:framework not found xxx 报错如下图: 解决办法:     Targets -> Build Se ...

  8. ReactiveObjC basic

    基础-> https://www.jianshu.com/p/cd4031fbf8ff 在RAC中,万物皆信号. RAC 指的就是 RactiveCocoa ,是 Github 的一个开源框架, ...

  9. ReactiveObjC(RAC)的使用汇总

    RAC 指的就是 RactiveCocoa ,是 Github 的一个开源框架,能够帮我们提供大量方便的事件处理方案,让我们更简单粗暴地去处理事件,现在分为 ReactiveObjC 和 Reacti ...

随机推荐

  1. 关于javascript中defineProperty的学习

    语法 Object.defineProperty(obj, prop, descriptor) 参数 obj 要在其上定义属性的对象. prop 要定义或修改的属性的名称. descriptor 将被 ...

  2. 集齐所有机制的按键控制LED驱动

    内核版本:linux2.6.22.6 硬件平台:JZ2440 驱动源码 final_key.c : #include <linux/module.h> #include <linux ...

  3. 两个java工程之间的相互调用方法

    如果你有两个java项目的话,如何向他们之间进行信息的通信前提:必须知道要通信的java项目(接收请求方)的服务器的IP地址和访问路径.其实两个java项目之间的通信还是使用HTTP的请求.主要有两种 ...

  4. 常用的shell脚本(安全方向)

    更多shell脚本参考:https://blog.51cto.com/zero01/2046242 1.拒绝密码撞库攻击的ip shell脚本:实现对登录主机失败10次以上的ip进行拒绝登录 #! / ...

  5. (4.1)mysql备份还原——mysql常见故障

    (4.1)mysql备份还原——mysql常见故障 1.常见故障类型 在数据库环境中,常见故障类型: 语句失败,用户进程失败,用户错误 实例失败,介质故障,网络故障 其中最严重的故障主要是用户错误和介 ...

  6. dedecms自定义表单提交成功后提示信息修改和跳转链接修改

    我们在用dedecms自定义表单提交成功后提示信息一般是"Dedecms 提示信息",这个要怎么改成自己想要的文字呢?还有就是提示页停留时间,目前估计就2秒,太快了,要如何设置长点 ...

  7. 装系统w7、ubuntu、centos等系统(一)

    装w7系统准备 1.从老毛桃u盘启动盘制作工具_老毛桃u盘装系统_老毛桃pe_老毛桃官网下载装机版 2.一个正常使用的U盘,但容量大于4G,并且插入电脑保持连接 3.老毛桃装机版选择U盘启动-> ...

  8. Scala泛型详解

    在Scala中你可以使用类型参数来实现类和函数,这样的类和函数可以用于多种类型.比如Array[T] 你可以存放任意指定类型T的数据. 类.特质.函数都可以有类型参数:将类型参数放在名字后面用方括号括 ...

  9. 【EatBook】-NO.2.EatBook.2.JavaArchitecture.1.001-《修炼Java开发技术在架构中体验设计模式和算法之美》-

    1.0.0 Summary Tittle:[EatBook]-NO.2.EatBook.2.JavaArchitecture.1.001-<修炼Java开发技术在架构中体验设计模式和算法之美&g ...

  10. MySQL高效的前提

    好硬件是数据库高效的前提,没有好硬件其他优化都是白费 高性能的CPU 主频高SQL处理的更快 3级cache大CPU计算速率更快 多线程,同时并发处理SQL 关闭NUMA并设置为最大性能模式,充分利用 ...