iOS_43_Reactivecocoa
2017-12-12 16:30
519 查看
Reactivecocoa在5.0以后将 RAC 拆分为四个库:ReactiveCocoa、ReactiveSwift、ReactiveObjC、ReactiveObjCBridge。
其中的ReactiveCocoa和ReactiveObjC,前一个适用于纯Swift项目,后一个适用于纯OC项目。
若项目为Swift和OC混编,那么需要将ReactiveObjC和ReactiveCocoa都导入,同时还需要手动导入ReactiveObjCBridge。
命令行:
touch podfile
open podfile
//pod search reactivecocoa
pod search reactiveobjc
// 如果搜索不到最新的reactivecocoa,就使用下面的命令,升级pod先
pod repo update
pod install
如果pod导入三方库后,头文件不显示,
那么在TARGETS -> Build Settings -> Search Paths -> User Header Search Paths 中 写入 ${SRCROOT} 再将后面参数改为recursive,就可以解决了.
纯OC代码的 podfile示例
RACSignal信号与订阅者
RACSubject使用
运行效果:
RACReplaySubject (可先发信号,再订阅信号)
RACSubject之代理示例
storyboard如下:
RedView如下:
控制器:
RACSequence集合类
model类
控制器
podfile
RAC的使用场景
storyboard如下:
控制器:
RACLiftSelector 多个请求完成后才执行某操作
RAC宏示例
storyboard
主控制器
//
// ViewController.m
// 13RAC常见宏
//
// Created by beyond on 2017/12/27.
// Copyright © 2017年 beyond. All rights reserved.
//
#import "ViewController.h"
#import "ReactiveObjC.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UITextField *textField;
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self rac_define_1];
[self rac_define_2];
[self rac_define_3];
[self rac_define_4];
}
- (void)rac_define_4
{
// 元组的包装和解包
// 将参数们包装成元组
RACTuple *tuple = RACTuplePack(@"龙与虎",@"逢坂大河");
NSLog(@"sg_%@_%@",tuple[0],tuple[1]);
// 将元组解包
RACTupleUnpack(NSString *anime,NSString *actress) = tuple;
NSLog(@"sg_%@_%@",anime,actress);
}
- (void)rac_define_3
{
// 解决block的循环引用问题,下面两个配套使用,外面+block里面
// 详细示例见NextViewCtrl
// @weakify(self)
// @strongify(self)
}
- (void)rac_define_2
{
// 监听某个对象的某个属性,返回值为信号
// 比如:监听label的文本,转化成信号
[RACObserve(_titleLabel, text) subscribeNext:^(id _Nullable newTextValue) {
NSLog(@"sg_%@",newTextValue);
}];
}
- (void)rac_define_1
{
// 对某个对象的某个属性绑定
// 比如:将label的文字 与 输入框的文本signal进行绑定
RAC(_titleLabel,text) = _textField.rac_textSignal;
}
@end
Next控制器(演示循环引用,nextViewCtrl消失时,dealloc未被执行)
//
// NextViewCtrl.m
// 13RAC常见宏
//
// Created by beyond on 2017/12/27.
// Copyright © 2017年 beyond. All rights reserved.
//
#import "NextViewCtrl.h"
#import "ReactiveObjC.h"
@interface NextViewCtrl ()
@property (nonatomic,strong) RACSignal *signal;
@end
@implementation NextViewCtrl
- (IBAction)dismissBtnClicked:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)viewDidLoad {
[super viewDidLoad];
// 演示 循环引用,出现内存泄露(控制器dismiss时dealloc没被调用)
// [self rac_define_memoryleak];
// 使用宏避免循环引用
[self rac_define_avoidMemoryLeak];
}
// 使用宏避免循环引用
- (void)rac_define_avoidMemoryLeak
{
// 先对self弱引用 (必须成对使用)
// 相当于把self变成弱指针
@weakify(self);
// 双方强引用的时候,会出现内存泄露
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
// 再在代码块内强引用 (必须成对使用)
// 对弱指针 又进行 强引用,目的是保证在代码块中不被销毁;强引用的范围仅限于代码块
@strongify(self);
// 经过上面的处理后,block中使用self已经不是一个强指针了
NSLog(@"sg__ctrl的self已经不会出现循环引用了_%@",self);
return nil;
}];
// self又对signal进行了强引用 (strong 属性的成员变量)
_signal = signal;
}
// 演示 循环引用,出现内存泄露(控制器dismiss时dealloc没被调用)
- (void)rac_define_memoryleak
{
// 双方强引用的时候,会出现内存泄露
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
// block中使用self,会对self进行了强引用
NSLog(@"sg__ctrl被强引用,无法被销毁_%@",self);
return nil;
}];
// self又对signal进行了强引用 (strong 属性的成员变量)
_signal = signal;
}
- (void)dealloc
{
NSLog(@"sg__dealloc__安全销毁__无内存泄漏");
}
@end
其中的ReactiveCocoa和ReactiveObjC,前一个适用于纯Swift项目,后一个适用于纯OC项目。
若项目为Swift和OC混编,那么需要将ReactiveObjC和ReactiveCocoa都导入,同时还需要手动导入ReactiveObjCBridge。
命令行:
touch podfile
open podfile
//pod search reactivecocoa
pod search reactiveobjc
// 如果搜索不到最新的reactivecocoa,就使用下面的命令,升级pod先
pod repo update
pod install
如果pod导入三方库后,头文件不显示,
那么在TARGETS -> Build Settings -> Search Paths -> User Header Search Paths 中 写入 ${SRCROOT} 再将后面参数改为recursive,就可以解决了.
纯OC代码的 podfile示例
source 'https://github.com/CocoaPods/Specs.git' platform :ios, ‘8.0’ use_frameworks! target “06RAC” do pod 'ReactiveObjC', '~> 3.0’ end
RACSignal信号与订阅者
// // ViewController.m // 06RAC // // Created by beyond on 2017/12/12. // Copyright © 2017年 beyond. All rights reserved. #import "ViewController.h" #import "ReactiveObjC.h" @interface ViewController () // 用一个成员变量,保存一下 信号内部创建的订阅者,防止信号被自动取消订阅(以便将来自己手动用RACDisposable取消订阅) @property (nonatomic,strong) id <RACSubscriber> subscriber; // 用一个成员变量,保存一下,以便将来自己手动用取消订阅 @property (nonatomic,strong) RACDisposable *disposable; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // 1.创建信号时,block_didSubscribe代码并未执行(只有在订阅了信号之后,才会执行block_didSubscribe) RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) { _subscriber = subscriber; // block_didSubscribe的作用是:描述当前信号的哪些数据需要发送 // block_didSubscribe会被保存到RACDynamicSignal的成员变量里 NSLog(@"sg_1_信号成功被激活,即将发送新的信号值"); // 3.只有订阅者RACPassthroughSubscriber才能发送信号的新值 [subscriber sendNext:@"新的信号值1"]; NSLog(@"sg_3_发送信号完毕"); return [RACDisposable disposableWithBlock:^{ // 默认会自动来到这个代码,一般作为信号被取消订阅时的清理收尾工作 // 注:但是,只要订阅者还在,就不会自动取消信号订阅(因此,要用成员变量保存一下subscriber) NSLog(@"sg_4_清理收尾"); }]; }]; NSLog(@"sg_即将订阅信号"); // 2.只有订阅信号后,默认的冷信号才会变成热信号! // nextBlockAfterValueChanged是当收到发送的信号改变后的新值时,要执行的代码 // 作用:2.1.创建订阅者 // 作用:2.2 .把nextBlockAfterValueChanged保存在了订阅者的成员变量里 _disposable = [signal subscribeNext:^(id _Nullable newValue) { // 只要[subscriber sendNext:@"新的信号值1"],就会调用这个nextBlockAfterValueChanged NSLog(@"sg_2_当订阅的信号发生改变时,要执行的代码_%@",newValue); }]; // 手动取消信号订阅 [_disposable dispose]; } @end /* * 信号类(RACSiganl),它本身不具备发送信号的能力,而是交给内部一个<订阅者>去发送新数据。 默认一个信号都是冷信号,只有这个信号被订阅了,这个信号才会变为热信号。 * 如何订阅信号:调用信号RACSignal的subscribeNext就能订阅了。 */ // RACSignal使用步骤: // 1.创建信号 + (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe // 2.订阅信号,就会激活信号. RACDynamicSignal的方法- (RACDisposable *)subscribeNext:(void (^)(id newValue))nextBlockAfterValueChanged // 3.由订阅者 发送信号.RACPassthroughSubscriber的方法 - (void)sendNext:(id)value // RACSignal底层实现: // 1.创建信号时,首先把block_didSubscribe保存到信号(RACDynamicSignal)的成员变量中. // 2.当信号被订阅,也就是调用RACDynamicSignal的方法- (RACDisposable *)subscribeNext:(void (^)(id newValue))nextBlockAfterValueChanged时.注意:nextBlockAfterValueChanged实际就是观察到信号改变后,要响应的操作 // 2.1 在上面的subscribeNext方法内部,会创建订阅者RACPassthroughSubscriber,并且把nextBlockAfterValueChanged保存到订阅者subscriber的成员变量中。 // 2.2 subscribeNext的方法内部会调用信号signal的成员变量block_didSubscribe,使信号变成了热信号. // 3.在信号siganl的block_didSubscribe中执行[subscriber sendNext:@"signal_newValue"]方法,即可以告诉订阅者信号变化后的新值. // 3.1 [subscriber sendNext:@"signal_newValue"]的底层于是会执行subscriber的成员变量nextBlockAfterValueChanged
RACSubject使用
// // ViewController.m // 07RACSubject // // Created by beyond on 2017/12/13. // Copyright © 2017年 beyond. All rights reserved. // #import "ViewController.h" #import "ReactiveObjC.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // RACSubject既可以充当信号,又可以发送信号!因为继承自RACSignal并实现了RACSubscriber协议 // 1.创建RACSubject信号 RACSubject *subject = [RACSubject subject]; // 2.订阅信号(RACSubject必须先订阅,再发送信号) // 不同的信号,处理订阅的方式不一样!!! // RACSubject处理订阅:仅仅是将创建的订阅者 到 成员变量数组里(subscribers) [subject subscribeNext:^(id _Nullable newValue) { NSLog(@"sg_第1个订阅者_newValue:%@",newValue); }]; // 注:因为是成员变量数组,所以可以多次订阅(会创建一个新的订阅者,并加入到成员变量数组里) [subject subscribeNext:^(id _Nullable newValue) { NSLog(@"sg_第2个订阅者_newValue:%@",newValue); }]; // 3.发送信号 [subject sendNext:@"这个是要发送给订阅者的新信号值"]; // 总结:核心思想,2点: // 底层实现:遍历成员数组里的所有订阅者,调用其nextBlock // 执行流程: // RACSubject被订阅,仅仅是保存创建的订阅者 到成员变量数组里(subscribers) // RACSubject发送数据,遍历成员变量数组里的所有的订阅者,然后调用他们的nextBlock } @end
运行效果:
RACReplaySubject (可先发信号,再订阅信号)
// // ViewController.m // 08RACReplaySubject // // Created by beyond on 2017/12/26. // Copyright © 2017年 beyond. All rights reserved. // #import "ViewController.h" #import "ReactiveObjC.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // 0.RACReplaySubject可先发送信号,再订阅信号 // 1.创建信号(RACReplaySubject新增了一个成员变量valuesReceived) RACReplaySubject *replaySubject = [RACReplaySubject subject]; // 3.发送信号仅仅是:将newValue保存到valuesArray中; // 然后调用父类RACSubject的sendNext方法:遍历所有的订阅者,将新数据发送出去 // 如果暂时还没有创建订阅者时(尚未被订阅),则不发送任何数据 [replaySubject sendNext:@"这个是新值"]; // 2.创建订阅者 // 注:会遍历valuesArray中所有的值,让新建的订阅者,[subscriber sentNext:value](即:执行下面的block) // 目的就是:让该新建的订阅者获得valuesArray中所有的新值 [replaySubject subscribeNext:^(id _Nullable newValue) { NSLog(@"sg_newValue:%@",newValue); }]; } @end
RACSubject之代理示例
storyboard如下:
RedView如下:
// // RedView.h // 09RACSubjectDemo // // Created by beyond on 2017/12/26. // Copyright © 2017年 beyond. All rights reserved. // #import <UIKit/UIKit.h> #import "ReactiveObjC.h" @interface RedView : UIView // 强引用 @property (nonatomic,strong) RACSubject *btnClickSignal; - (IBAction)btnClicked:(UIButton *)sender; @end
// // RedView.m // 09RACSubjectDemo // // Created by beyond on 2017/12/26. // Copyright © 2017年 beyond. All rights reserved. // #import "RedView.h" @implementation RedView // 懒加载 - (RACSubject *)btnClickSignal { if (_btnClickSignal == nil) { // 1.创建信号 _btnClickSignal = [RACSubject subject]; } return _btnClickSignal; } // 按钮点击 - (void)btnClicked:(UIButton *)sender { // 3.发送信号 [self.btnClickSignal sendNext:@"newValue"]; } @end
控制器:
// // ViewController.h // 09RACSubjectDemo // // Created by beyond on 2017/12/26. // Copyright © 2017年 beyond. All rights reserved. // #import <UIKit/UIKit.h> #import "RedView.h" @interface ViewController : UIViewController @property (nonatomic,weak) IBOutlet RedView *redView; @end
// // ViewController.m // 09RACSubjectDemo // // Created by beyond on 2017/12/26. // Copyright © 2017年 beyond. All rights reserved. // #import "ViewController.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // 订阅信号 [_redView.btnClickSignal subscribeNext:^(id _Nullable newValue) { NSLog(@"sg_%@",newValue); }]; } @end
RACSequence集合类
model类
// // AnimeModel.h // 10RAC集合类 // // Created by beyond on 2017/12/26. // Copyright © 2017年 beyond. All rights reserved. // #import <Foundation/Foundation.h> @interface AnimeModel : NSObject @property (nonatomic,copy) NSString *anime; @property (nonatomic,copy) NSString *actress; @end
控制器
// // ViewController.m // 10RAC集合类 // // Created by beyond on 2017/12/26. // Copyright © 2017年 beyond. All rights reserved. // #import "ViewController.h" #import "ReactiveObjC.h" #import "MJExtension.h" #import "AnimeModel.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // [self tuple]; // [self sequence_arr]; // [self sequence_dic]; [self sequence_dictArrToModelArr]; } - (void)sequence_dictArrToModelArr { // 将从Plist转化而来的字典数组,转成对象数组 NSArray *dictArrFromPlist = @[ @{@"anime":@"k-on", @"actress":@"平泽唯" }, @{@"anime":@"龙与虎", @"actress":@"逢坂大河" }, @{@"anime":@"未闻花名", @"actress":@"面码" }, @{@"anime":@"狼与香辛料", @"actress":@"赫萝" }, @{@"anime":@"俺妹", @"actress":@"黑猫" } ]; NSMutableArray *modelArr = [NSMutableArray array]; // 方法1:遍历信号的每一个值(即dict) [dictArrFromPlist.rac_sequence.signal subscribeNext:^(NSDictionary *dict) { AnimeModel *model = [AnimeModel mj_objectWithKeyValues:dict]; [modelArr addObject:model]; }]; // 方法2:直接mjextension modelArr = [AnimeModel mj_objectArrayWithKeyValuesArray:dictArrFromPlist]; NSLog(@"sg_modelArr:%@",modelArr); // 方法3:sequence高级用法map NSArray *modelArr2 = [[dictArrFromPlist.rac_sequence map:^id _Nullable(NSDictionary *dict) { // block返回一个对象,从遍历中的字典转化而来的对象,重新放回到sequence集合里 return [AnimeModel mj_objectWithKeyValues:dict]; // 最后将转化完成的Sequence集合,转成NSArray }] array]; NSLog(@"sg_modelArr2:%@",modelArr2); } - (void)sequence_dic { // RAC中的集合类,用于统一数组和字典 NSDictionary *dic = @{ @"k-on":@"平泽唯", @"龙与虎":@"逢坂大河", @"未闻花名":@"面码", @"狼与香辛料":@"赫萝", @"俺妹":@"黑猫" }; [dic.rac_sequence.signal subscribeNext:^(RACTwoTuple *obj) { // NSString *key = obj[0]; // NSString *value = obj[1]; // NSLog(@"sg_遍历:%@_%@",key,value); // 或者使用:强大的宏 RACTupleUnpack(NSString *key,NSString *value) = obj; NSLog(@"sg_遍历:%@_%@",key,value); }]; } - (void)sequence_arr { // RAC中的集合类,用于统一数组和字典 NSArray *arr = @[@"k-on",@"大河",@"面码",@"赫萝",@"黑猫"]; // 1.数组先转成sequence RACSequence *sequence = arr.rac_sequence; // 2.sequence再转成信号 RACSignal *signal = sequence.signal; // 3.再订阅信号,则会自动遍历 [signal subscribeNext:^(id _Nullable obj) { NSLog(@"sg_遍历:%@",obj); }]; // 综上所述 [arr.rac_sequence.signal subscribeNext:^(id _Nullable obj) { NSLog(@"sg_遍历2:%@",obj); }]; } - (void)tuple { // 类似于NSArray,只能放对象 RACTuple *tuple = [RACTuple tupleWithObjects:@"N2",@"N1",@2018, nil]; NSLog(@"sg_%@",tuple); NSLog(@"sg_%@",tuple[0]); } @end
podfile
source 'https://github.com/CocoaPods/Specs.git' platform :ios, ‘8.0’ use_frameworks! target “10RAC集合类” do pod 'ReactiveObjC', '~> 3.0’ pod 'MJExtension', '~> 3.0’ end
RAC的使用场景
storyboard如下:
控制器:
// // ViewController.h // 11RAC场景 // // Created by beyond on 2017/12/26. // Copyright © 2017年 beyond. All rights reserved. // #import <UIKit/UIKit.h> #import "RedView.h" @interface ViewController : UIViewController @property (weak, nonatomic) IBOutlet RedView *redView; @property (weak, nonatomic) IBOutlet UIButton *btn; @property (weak, nonatomic) IBOutlet UITextField *textField; @end
// // ViewController.m // 11RAC场景 // // Created by beyond on 2017/12/26. // Copyright © 2017年 beyond. All rights reserved. // #import "ViewController.h" #import "ReactiveObjC.h" #import "UIView+Frame.h" // 注:rac_observeKeyPath的方法,默认情况下,并没有导入到主头文件中,需手动导入 #import "NSObject+RACKVOWrapper.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // 0.判断方法是否被执行 // [self rac_signal_for_selector]; // [self rac_signal_for_selector2]; // 1.rac代替代理 // [self rac_replace_delegate]; // 2.rac代替KVO // [self rac_replace_kvo]; // [self rac_replace_kvo2]; // 3.rac监听事件,如按钮点击 // [self rac_replace_controlEvent]; // 4.rac代替通知 // [self rac_replace_notification]; // 5.监听文本框的文字 [self rac_replace_textFieldListen]; } - (void)rac_replace_textFieldListen { // rac 监听 文本的改变 [[_textField rac_textSignal] subscribeNext:^(NSString * _Nullable x) { NSLog(@"sg__textField has changed:%@",x); }]; } - (void)rac_replace_notification { // rac代替通知,将通知中心监听到的通知转成信号 [[[NSNotificationCenter defaultCenter]rac_addObserverForName:UIKeyboardWillShowNotification object:nil] subscribeNext:^(NSNotification * _Nullable concretNotification) { /* sg_监听到了键盘将要弹出的通知:NSConcreteNotification 0x6000002562f0 {name = UIKeyboardWillShowNotification; userInfo = { UIKeyboardAnimationCurveUserInfoKey = 7; UIKeyboardAnimation Duration UserInfoKey = "0.25"; UIKeyboard Bounds UserInfoKey = "NSRect: {{0, 0}, {320, 253}}"; UIKeyboard CenterBegin UserInfoKey = "NSPoint: {160, 460}"; UIKeyboard CenterEnd UserInfoKey = "NSPoint: {160, 441.5}"; UIKeyboard FrameBegin UserInfoKey = "NSRect: {{0, 352}, {320, 216}}"; UIKeyboard FrameEnd UserInfoKey = "NSRect: {{0, 315}, {320, 253}}"; UIKeyboard IsLocal UserInfoKey = 1; }} */ NSLog(@"sg_监听到了键盘将要 弹出 的通知:%@",concretNotification); }]; // rac代替通知,将通知中心监听到的通知转成信号 [[[NSNotificationCenter defaultCenter]rac_addObserverForName:UIKeyboardDidHideNotification object:nil] subscribeNext:^(NSNotification * _Nullable concretNotification) { /* sg_监听到了键盘将要关闭的通知:NSConcreteNotification 0x600000243ed0 {name = UIKeyboardDidHideNotification; userInfo = { UIKeyboard Bounds UserInfoKey = "NSRect: {{0, 0}, {320, 253}}"; UIKeyboard CenterBegin UserInfoKey = "NSPoint: {160, 441.5}"; UIKeyboard CenterEnd UserInfoKey = "NSPoint: {160, 694.5}"; UIKeyboard FrameBegin UserInfoKey = "NSRect: {{0, 315}, {320, 253}}"; UIKeyboard FrameEnd UserInfoKey = "NSRect: {{0, 568}, {320, 253}}"; }} */ NSLog(@"sg_监听到了键盘将要 关闭 的通知:%@",concretNotification); }]; } - (void)rac_replace_controlEvent { // rac监听按钮点击事件,将事件转化成signal [[self.btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable btn) { // sg_监听到了按钮的controlEvent:<UIButton: 0x7fcb16507130; frame = (83.5 144; 153 30); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x610000232b20>> NSLog(@"sg_监听到了按钮的controlEvent:%@",btn); }]; } - (void)rac_replace_kvo2 { // rac代替kvo,监听redView的frame发生新值的改变 [[_redView rac_valuesForKeyPath:@"frame" observer:nil] subscribeNext:^(id _Nullable newValue) { // 启动时就打印了一次sg_newValue:NSRect: {{67.5, 273.5}, {240, 120}} // touch屏幕时,又打印了一次sg_newValue:NSRect: {{0, 224}, {240, 120}} NSLog(@"sg_newValue:%@",newValue); }]; } - (void)rac_replace_kvo { // rac代替kvo,监听redView的frame发生新值的改变 // 注意,此方法的缺点是: // rac_observeKeyPath的方法,默认情况下,并没有导入到主头文件中,需手动导入 [_redView rac_observeKeyPath:@"frame" options:NSKeyValueObservingOptionNew observer:nil block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) { // sg_NSRect: {{0, 224}, {240, 120}} // 注意:NS开头为NextStep,与Mac开发同源 NSLog(@"sg_%@",value); }]; } - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { _redView.x = 0; } - (void)rac_signal_for_selector2 { // 控制器 监听redView中的按钮有没有被点击 // 好处是:监听某个对象有没有调用某个方法 // 坏处是:不能传递参数(要传递数据就用RACSubject) [[_redView rac_signalForSelector:@selector(btnClicked:)]subscribeNext:^(RACTuple * _Nullable x) { /* <RACTuple: 0x61800001b890> ( "<UIButton: 0x7ff1b5e08570; frame = (137 269; 46 30); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x608000038540>>" ) */ NSLog(@"sg_控制器 感知到了 redView中的btnClick_%@",x); }]; } - (void)rac_signal_for_selector { // 将方法订阅成信号,从而判断方法是否被触发(执行) // 好处是:监听某个对象有没有调用某个方法 // 坏处是:不能传递参数(要传递数据就用RACSubject) [[self rac_signalForSelector:@selector(didReceiveMemoryWarning)] subscribeNext:^(RACTuple * _Nullable x) { // x是一个空的RACTuple NSLog(@"sg_控制器的didReceiveMemoryWarning方法被触发了_%@",x); }]; } - (void)rac_replace_delegate { // 参照RACSubject那个示例代码 } @end
RACLiftSelector 多个请求完成后才执行某操作
// // ViewController.m // 12RAC多次请求 // // Created by beyond on 2017/12/27. // Copyright © 2017年 beyond. All rights reserved. // #import "ViewController.h" #import "ReactiveObjC.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; [self rac_lift_selector]; } - (void)rac_lift_selector { RACSignal *signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) { NSLog(@"sg_模拟网络操作1"); [subscriber sendNext:@"sg_返回的网络数据1"]; return nil; }]; RACSignal *signal2 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) { NSLog(@"sg_模拟网络操作2"); [subscriber sendNext:@"sg_返回的网络数据2"]; return nil; }]; NSArray *signalArr = @[signal1,signal2]; // rac 实现 所有网络请求都完成的时候,才更新UI操作 // 注意:所有请求完成时才执行的方法的 参数 必须 和信号的个数 一一对应 [self rac_liftSelector:@selector(updateUIWithData1:andData2:) withSignalsFromArray:signalArr]; } - (void)updateUIWithData1:(id)x1 andData2:(id)x2 { NSLog(@"sg_所有请求都完成时,才被执行_x1:%@,x2:%@",x1,x2); } @end
RAC宏示例
storyboard
主控制器
//
// ViewController.m
// 13RAC常见宏
//
// Created by beyond on 2017/12/27.
// Copyright © 2017年 beyond. All rights reserved.
//
#import "ViewController.h"
#import "ReactiveObjC.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UITextField *textField;
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self rac_define_1];
[self rac_define_2];
[self rac_define_3];
[self rac_define_4];
}
- (void)rac_define_4
{
// 元组的包装和解包
// 将参数们包装成元组
RACTuple *tuple = RACTuplePack(@"龙与虎",@"逢坂大河");
NSLog(@"sg_%@_%@",tuple[0],tuple[1]);
// 将元组解包
RACTupleUnpack(NSString *anime,NSString *actress) = tuple;
NSLog(@"sg_%@_%@",anime,actress);
}
- (void)rac_define_3
{
// 解决block的循环引用问题,下面两个配套使用,外面+block里面
// 详细示例见NextViewCtrl
// @weakify(self)
// @strongify(self)
}
- (void)rac_define_2
{
// 监听某个对象的某个属性,返回值为信号
// 比如:监听label的文本,转化成信号
[RACObserve(_titleLabel, text) subscribeNext:^(id _Nullable newTextValue) {
NSLog(@"sg_%@",newTextValue);
}];
}
- (void)rac_define_1
{
// 对某个对象的某个属性绑定
// 比如:将label的文字 与 输入框的文本signal进行绑定
RAC(_titleLabel,text) = _textField.rac_textSignal;
}
@end
Next控制器(演示循环引用,nextViewCtrl消失时,dealloc未被执行)
//
// NextViewCtrl.m
// 13RAC常见宏
//
// Created by beyond on 2017/12/27.
// Copyright © 2017年 beyond. All rights reserved.
//
#import "NextViewCtrl.h"
#import "ReactiveObjC.h"
@interface NextViewCtrl ()
@property (nonatomic,strong) RACSignal *signal;
@end
@implementation NextViewCtrl
- (IBAction)dismissBtnClicked:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)viewDidLoad {
[super viewDidLoad];
// 演示 循环引用,出现内存泄露(控制器dismiss时dealloc没被调用)
// [self rac_define_memoryleak];
// 使用宏避免循环引用
[self rac_define_avoidMemoryLeak];
}
// 使用宏避免循环引用
- (void)rac_define_avoidMemoryLeak
{
// 先对self弱引用 (必须成对使用)
// 相当于把self变成弱指针
@weakify(self);
// 双方强引用的时候,会出现内存泄露
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
// 再在代码块内强引用 (必须成对使用)
// 对弱指针 又进行 强引用,目的是保证在代码块中不被销毁;强引用的范围仅限于代码块
@strongify(self);
// 经过上面的处理后,block中使用self已经不是一个强指针了
NSLog(@"sg__ctrl的self已经不会出现循环引用了_%@",self);
return nil;
}];
// self又对signal进行了强引用 (strong 属性的成员变量)
_signal = signal;
}
// 演示 循环引用,出现内存泄露(控制器dismiss时dealloc没被调用)
- (void)rac_define_memoryleak
{
// 双方强引用的时候,会出现内存泄露
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
// block中使用self,会对self进行了强引用
NSLog(@"sg__ctrl被强引用,无法被销毁_%@",self);
return nil;
}];
// self又对signal进行了强引用 (strong 属性的成员变量)
_signal = signal;
}
- (void)dealloc
{
NSLog(@"sg__dealloc__安全销毁__无内存泄漏");
}
@end
相关文章推荐
- iOS Reactivecocoa(RAC)知其所以然(源码分析,一篇足以)
- iOS ReactiveCocoa 最全常用API整理(可做为手册查询)
- ReactiveCocoa - iOS开发的新框架
- [转] iOS --- ReactiveCocoa - iOS开发的新框架
- IOS-43-导航栏标题navigationItem.title不能改变颜色的两种解决方法
- IOS ReactiveCoCoa初学总结
- 使用AFNetWorking和ReactiveCocoa对网络请求进行封装(仿煎蛋iOS)(3)
- iOS开发>学无止境 - 这样好用的ReactiveCocoa,根本停不下来
- iOS学习笔记(29) 爱不释手的ReactiveCocoa之UIButton
- iOS 第三方框架 - ReactiveCocoa学习2
- ReactiveCocoa - iOS开发的新框架
- ReactiveCocoa - iOS开发的新框架
- ReactiveCocoa - iOS开发的新框架
- iOS开发基础知识--碎片43
- iOS 更新xcode7.3后ReactiveCocoa中的weak问题的解决方法
- iOS 开发之 ReactiveCocoa 下的 MVVM(干货分享)
- ReactiveCocoa - iOS开发的新框架
- 基于AFNetworking2.0和ReactiveCocoa2.1的iOS REST Client
- ReactiveCocoa - iOS开发的新框架
- IOS学习笔记43--IOS App在ItunesConnect里面的几种状态