版本记录
版本号 | 时间 |
---|---|
V1.0 | 2017.08.07 |
前言
RAC可以简化很多我们的代码,具有很大的天然优势,还是要学一学的,我接下来这几篇就从ReactiveCocoa的基础到深入和大家说一下RAC的使用方法,希望对自己对大家有所帮助。感兴趣的可以看我上面写的这篇。
1. RAC详细解析(一)—— 框架概览
基本使用方法
这一篇就说一下几种主要的使用方法,都是很基础的使用。
1. Target - Action响应的使用
这种目标-动作模式可以用RAC来实现。
系统UIButton响应事件
#import "JJRACUseVC.h"
#import "Masonry.h"
#import "ReactiveCocoa/ReactiveCocoa.h"
@interface JJRACUseVC ()
@end
@implementation JJRACUseVC
#pragma mark - Override Base Function
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = @"RAC的基本使用";
self.view.backgroundColor = [UIColor lightTextColor];
[self loadOriginalButton];
}
#pragma mark - Object Private Function
- (void)loadOriginalButton
{
UIButton *startButton = [UIButton buttonWithType:UIButtonTypeCustom];
startButton.backgroundColor = [UIColor lightTextColor];
[startButton setTitle:@"开始" forState:UIControlStateNormal];
startButton.titleLabel.font = [UIFont boldSystemFontOfSize:25.0];
[startButton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
[startButton addTarget:self action:@selector(startButtonDidClick:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:startButton];
[startButton sizeToFit];
[startButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.equalTo(self.view);
}];
}
#pragma mark - Action && Notification
- (void)startButtonDidClick:(UIButton *)button
{
NSLog(@"被点击了");
}
@end
看结果输出
2017-08-07 15:23:27.646651+0800 JJOC[8093:3264727] 被点击了
2017-08-07 15:23:27.929708+0800 JJOC[8093:3264727] 被点击了
RAC改造后UIButton响应事件
#import "JJRACUseVC.h"
#import "Masonry.h"
#import "ReactiveCocoa/ReactiveCocoa.h"
@interface JJRACUseVC ()
@end
@implementation JJRACUseVC
#pragma mark - Override Base Function
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = @"RAC的基本使用";
self.view.backgroundColor = [UIColor lightTextColor];
[self loadOriginalButton];
}
#pragma mark - Object Private Function
- (void)loadOriginalButton
{
UIButton *startButton = [UIButton buttonWithType:UIButtonTypeCustom];
startButton.backgroundColor = [UIColor lightTextColor];
[startButton setTitle:@"开始" forState:UIControlStateNormal];
startButton.titleLabel.font = [UIFont boldSystemFontOfSize:25.0];
[startButton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:startButton];
[startButton sizeToFit];
[startButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.equalTo(self.view);
}];
[[startButton rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
NSLog(@"RAC被点击了");
}];
}
@end
看一下结果输出
2017-08-07 15:28:06.119778+0800 JJOC[8096:3265805] RAC被点击了
从上面可以看到,系统的给按钮添加响应的方法
[startButton addTarget:self action:@selector(startButtonDidClick:) forControlEvents:UIControlEventTouchUpInside];
- (void)startButtonDidClick:(UIButton *)button
{
NSLog(@"被点击了");
}
被RAC中下面的方法取代了。
[[startButton rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
NSLog(@"RAC被点击了");
}];
这样有一个优点就是代码更简洁和集中。
除了UIButton
,UITextField
也可以这么使用和改造。
下面我们接着看一下点击手势UITapGestureRecognizer
方面RAC
的应用。
系统UITapGestureRecognizer手势
#import "JJRACUseVC.h"
#import "Masonry.h"
#import "ReactiveCocoa/ReactiveCocoa.h"
@interface JJRACUseVC ()
@end
@implementation JJRACUseVC
#pragma mark - Override Base Function
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = @"RAC的基本使用";
self.view.backgroundColor = [UIColor lightTextColor];
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(gestureDidTapped:)];
[self.view addGestureRecognizer:tapGesture];
}
#pragma mark - Action && Notification
- (void)gestureDidTapped:(UITapGestureRecognizer *)tapGesture
{
NSLog(@"点击手势");
}
@end
看结果输出
2017-08-07 15:49:45.122845+0800 JJOC[8100:3269324] 点击手势
RAC改造手势UITapGestureRecognizer
#import "JJRACUseVC.h"
#import "Masonry.h"
#import "ReactiveCocoa/ReactiveCocoa.h"
@interface JJRACUseVC ()
@end
@implementation JJRACUseVC
#pragma mark - Override Base Function
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = @"RAC的基本使用";
self.view.backgroundColor = [UIColor lightTextColor];
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] init];
[[tapGesture rac_gestureSignal] subscribeNext:^(id x) {
NSLog(@"点击手势");
}];
[self.view addGestureRecognizer:tapGesture];
}
@end
下面看输出结果
2017-08-07 15:52:44.342459+0800 JJOC[8105:3270075] 点击手势
2. 通知 - NSNotification
通知是我们总用的一种通信机制,RAC中也可以对通知进行改造,下面我们先看一下系统的通知。
系统通知NSNotification
1. JJRACNotificationAddVC.m
#import "JJRACNotificationAddVC.h"
#import "ReactiveCocoa/ReactiveCocoa.h"
#import "JJRACNotificationPostVC.h"
@interface JJRACNotificationAddVC ()
@end
@implementation JJRACNotificationAddVC
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = @"RAC的基本使用";
self.view.backgroundColor = [UIColor lightTextColor];
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] init];
[[tapGesture rac_gestureSignal] subscribeNext:^(id x) {
JJRACNotificationPostVC *postVC = [[JJRACNotificationPostVC alloc] init];
[self.navigationController pushViewController:postVC animated:YES];
}];
[self.view addGestureRecognizer:tapGesture];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveNotification:) name:@"notification" object:nil];
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
#pragma mark - Action && Notification
- (void)didReceiveNotification:(NSNotification *)noti
{
NSLog(@"收到通知了");
}
@end
2. JJRACNotificationPostVC.m
#import "JJRACNotificationPostVC.h"
@interface JJRACNotificationPostVC ()
@end
@implementation JJRACNotificationPostVC
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] postNotificationName:@"notification" object:nil userInfo:nil];
}
@end
下面看输出结果
2017-08-07 16:04:31.352838+0800 JJOC[8108:3271268] 收到通知了
2017-08-07 16:04:46.500606+0800 JJOC[8108:3271268] 收到通知了
RAC改造通知NSNotification
#import "JJRACNotificationAddVC.h"
#import "ReactiveCocoa/ReactiveCocoa.h"
#import "JJRACNotificationPostVC.h"
@interface JJRACNotificationAddVC ()
@end
@implementation JJRACNotificationAddVC
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = @"RAC的基本使用";
self.view.backgroundColor = [UIColor lightTextColor];
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] init];
[[tapGesture rac_gestureSignal] subscribeNext:^(id x) {
JJRACNotificationPostVC *postVC = [[JJRACNotificationPostVC alloc] init];
[self.navigationController pushViewController:postVC animated:YES];
}];
[self.view addGestureRecognizer:tapGesture];
[[[NSNotificationCenter defaultCenter] rac_addObserverForName:@"notification" object:nil] subscribeNext:^(id x) {
NSLog(@"收到通知了");
}];
}
@end
看输出结果
2017-08-07 16:08:02.155427+0800 JJOC[8111:3271927] 收到通知了
注意:RAC
中的通知不需要remove observer
,因为在rac_addObserverForName
方法中他已经写了remove
。
3. 键值观察 - KVO
系统键值观察KVO
下面直接看代码。
#import "JJRACKVOVC.h"
@interface JJRACKVOVC ()
@property (nonatomic, strong) UITableView *tableView;
@end
@implementation JJRACKVOVC
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = @"KVO键值观察";
self.view.backgroundColor = [UIColor lightTextColor];
[self setupUI];
}
- (void)dealloc
{
[self.tableView removeObserver:self forKeyPath:@"contentOffset"];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
if (object == self.tableView && [keyPath isEqualToString:@"contentOffset"]) {
NSLog(@"%f~~%f",self.tableView.contentOffset.x,self.tableView.contentOffset.y);
NSLog(@"%@",change[NSKeyValueChangeNewKey]);
}
else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
#pragma mark - Object Private Function
- (void)setupUI
{
UITableView *tableView = [[UITableView alloc] initWithFrame:self.view.frame style:UITableViewStylePlain];
tableView.contentSize = CGSizeMake(2000, 2000);
[self.view addSubview:tableView];
self.tableView = tableView;
[self.tableView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:nil];
}
@end
下面看输出结果
2017-08-07 16:40:49.452546+0800 JJOC[8122:3275485] 0.000000~~-59.000000
2017-08-07 16:40:49.452850+0800 JJOC[8122:3275485] NSPoint: {0, -59}
2017-08-07 16:40:49.469207+0800 JJOC[8122:3275485] 0.000000~~-59.500000
2017-08-07 16:40:49.469515+0800 JJOC[8122:3275485] NSPoint: {0, -59.5}
2017-08-07 16:40:49.486055+0800 JJOC[8122:3275485] 0.000000~~-60.500000
2017-08-07 16:40:49.486352+0800 JJOC[8122:3275485] NSPoint: {0, -60.5}
2017-08-07 16:40:49.502573+0800 JJOC[8122:3275485] 0.000000~~-61.000000
2017-08-07 16:40:49.502872+0800 JJOC[8122:3275485] NSPoint: {0, -61}
这里面还有几个常量需要简单说明一下。
首先是[self.tableView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:nil]
里面的枚举NSKeyValueObservingOptions
enum {
// 提供属性的新值
NSKeyValueObservingOptionNew = 0x01,
// 提供属性的旧值
NSKeyValueObservingOptionOld = 0x02,
// 如果指定,则在添加观察者的时候立即发送一个通知给观察者,
// 并且是在注册观察者方法返回之前
NSKeyValueObservingOptionInitial = 0x04,
// 如果指定,则在每次修改属性时,会在修改通知被发送之前预先发送一条通知给观察者,
// 这与-willChangeValueForKey:被触发的时间是相对应的。
// 这样,在每次修改属性时,实际上是会发送两条通知。
NSKeyValueObservingOptionPrior = 0x08
};
typedef NSUInteger NSKeyValueObservingOptions;
然后是- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
中change
字典中的键。
// 属性变化的类型,是一个NSNumber对象,包含NSKeyValueChange枚举相关的值
NSString *const NSKeyValueChangeKindKey;
// 属性的新值。当NSKeyValueChangeKindKey是 NSKeyValueChangeSetting,
// 且添加观察的方法设置了NSKeyValueObservingOptionNew时,我们能获取到属性的新值。
// 如果NSKeyValueChangeKindKey是NSKeyValueChangeInsertion或者NSKeyValueChangeReplacement,
// 且指定了NSKeyValueObservingOptionNew时,则我们能获取到一个NSArray对象,包含被插入的对象或
// 用于替换其它对象的对象。
NSString *const NSKeyValueChangeNewKey;
// 属性的旧值。当NSKeyValueChangeKindKey是 NSKeyValueChangeSetting,
// 且添加观察的方法设置了NSKeyValueObservingOptionOld时,我们能获取到属性的旧值。
// 如果NSKeyValueChangeKindKey是NSKeyValueChangeRemoval或者NSKeyValueChangeReplacement,
// 且指定了NSKeyValueObservingOptionOld时,则我们能获取到一个NSArray对象,包含被移除的对象或
// 被替换的对象。
NSString *const NSKeyValueChangeOldKey;
// 如果NSKeyValueChangeKindKey的值是NSKeyValueChangeInsertion、NSKeyValueChangeRemoval
// 或者NSKeyValueChangeReplacement,则这个key对应的值是一个NSIndexSet对象,
// 包含了被插入、移除或替换的对象的索引
NSString *const NSKeyValueChangeIndexesKey;
// 当指定了NSKeyValueObservingOptionPrior选项时,在属性被修改的通知发送前,
// 会先发送一条通知给观察者。我们可以使用NSKeyValueChangeNotificationIsPriorKey
// 来获取到通知是否是预先发送的,如果是,获取到的值总是@(YES)
NSString *const NSKeyValueChangeNotificationIsPriorKey;
这里面NSKeyValueChangeKindKey
是由如下的枚举定义的。
/* Possible values in the NSKeyValueChangeKindKey entry in change dictionaries. See the comments for -observeValueForKeyPath:ofObject:change:context: for more information.
*/
typedef NS_ENUM(NSUInteger, NSKeyValueChange) {
NSKeyValueChangeSetting = 1,
NSKeyValueChangeInsertion = 2,
NSKeyValueChangeRemoval = 3,
NSKeyValueChangeReplacement = 4,
};
RAC改造后键值观察KVO
#import "JJRACKVOVC.h"
#import "ReactiveCocoa/ReactiveCocoa.h"
@interface JJRACKVOVC ()
@property (nonatomic, strong) UITableView *tableView;
@end
@implementation JJRACKVOVC
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = @"KVO键值观察";
self.view.backgroundColor = [UIColor lightTextColor];
[self setupUI];
}
#pragma mark - Object Private Function
- (void)setupUI
{
UITableView *tableView = [[UITableView alloc] initWithFrame:self.view.frame style:UITableViewStylePlain];
tableView.contentSize = CGSizeMake(2000, 2000);
[self.view addSubview:tableView];
self.tableView = tableView;
[RACObserve(self.tableView, contentOffset) subscribeNext:^(id x) {
NSLog(@"%f~~%f",self.tableView.contentOffset.x,self.tableView.contentOffset.y);
}];
}
@end
下面看输出结果
2017-08-07 16:54:53.739141+0800 JJOC[8129:3279063] 0.000000~~-56.500000
2017-08-07 16:54:53.759018+0800 JJOC[8129:3279063] 0.000000~~-57.500000
2017-08-07 16:54:53.775475+0800 JJOC[8129:3279063] 0.000000~~-58.500000
2017-08-07 16:54:53.792334+0800 JJOC[8129:3279063] 0.000000~~-59.000000
2017-08-07 16:54:53.808930+0800 JJOC[8129:3279063] 0.000000~~-60.000000
2017-08-07 16:54:53.825839+0800 JJOC[8129:3279063] 0.000000~~-60.500000
2017-08-07 16:54:53.842181+0800 JJOC[8129:3279063] 0.000000~~-61.000000
2017-08-07 16:54:53.859100+0800 JJOC[8129:3279063] 0.000000~~-61.500000
2017-08-07 16:54:53.875383+0800 JJOC[8129:3279063] 0.000000~~-61.500000
2017-08-07 16:54:53.889271+0800 JJOC[8129:3279063] 0.000000~~-62.000000
2017-08-07 16:54:53.908936+0800 JJOC[8129:3279063] 0.000000~~-62.500000
2017-08-07 16:54:53.925394+0800 JJOC[8129:3279063] 0.000000~~-62.500000
2017-08-07 16:54:53.938987+0800 JJOC[8129:3279063] 0.000000~~-62.500000
2017-08-07 16:54:53.955523+0800 JJOC[8129:3279063] 0.000000~~-63.000000
2017-08-07 16:54:53.974787+0800 JJOC[8129:3279063] 0.000000~~-63.000000
2017-08-07 16:54:53.989017+0800 JJOC[8129:3279063] 0.000000~~-63.000000
4. 代理 - delegate
系统代理实现 - delegate
#import "JJRACDelegateVC.h"
@interface JJRACDelegateVC () <UIScrollViewDelegate>
@property (nonatomic, strong) UITableView *tableView;
@end
@implementation JJRACDelegateVC
#pragma mark - Override Base Function
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = @"代理RAC";
self.view.backgroundColor = [UIColor lightTextColor];
[self setupUI];
}
#pragma mark - Object Private Function'
- (void)setupUI
{
UITableView *tableView = [[UITableView alloc] initWithFrame:self.view.frame style:UITableViewStylePlain];
tableView.contentSize = CGSizeMake(2000, 2000);
tableView.delegate = self;
[self.view addSubview:tableView];
self.tableView = tableView;
}
#pragma mark - UIScrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
NSLog(@"%f~~%f",scrollView.contentOffset.x,scrollView.contentOffset.y);
}
@end
看一下输出结果
2017-08-07 17:01:03.688621+0800 JJOC[8132:3279828] 0.000000~~-43.000000
2017-08-07 17:01:03.705258+0800 JJOC[8132:3279828] 0.000000~~-46.500000
2017-08-07 17:01:03.721466+0800 JJOC[8132:3279828] 0.000000~~-49.000000
2017-08-07 17:01:03.738735+0800 JJOC[8132:3279828] 0.000000~~-51.500000
2017-08-07 17:01:03.754964+0800 JJOC[8132:3279828] 0.000000~~-53.500000
2017-08-07 17:01:03.771588+0800 JJOC[8132:3279828] 0.000000~~-55.000000
2017-08-07 17:01:03.784926+0800 JJOC[8132:3279828] 0.000000~~-56.500000
2017-08-07 17:01:03.801667+0800 JJOC[8132:3279828] 0.000000~~-57.500000
2017-08-07 17:01:03.818327+0800 JJOC[8132:3279828] 0.000000~~-58.500000
2017-08-07 17:01:03.838312+0800 JJOC[8132:3279828] 0.000000~~-59.500000
RAC实现代理方法
#import "JJRACDelegateVC.h"
#import "ReactiveCocoa/ReactiveCocoa.h"
@interface JJRACDelegateVC () <UIScrollViewDelegate>
@property (nonatomic, strong) UITableView *tableView;
@end
@implementation JJRACDelegateVC
#pragma mark - Override Base Function
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = @"代理RAC";
self.view.backgroundColor = [UIColor lightTextColor];
[self setupUI];
[[self rac_signalForSelector:@selector(scrollViewDidScroll:) fromProtocol:@protocol(UIScrollViewDelegate)] subscribeNext:^(RACTuple *tuple) {
NSLog(@"%@",tuple);
NSLog(@"%f~~%f",self.tableView.contentOffset.x,self.tableView.contentOffset.y);
}];
//这里是个坑,必须将代理最后设置,否则信号是无法订阅到的
self.tableView.delegate = self;
}
#pragma mark - Object Private Function'
- (void)setupUI
{
UITableView *tableView = [[UITableView alloc] initWithFrame:self.view.frame style:UITableViewStylePlain];
tableView.contentSize = CGSizeMake(2000, 2000);
[self.view addSubview:tableView];
self.tableView = tableView;
}
@end
下面看输出结果
2017-08-07 17:34:15.382048+0800 JJOC[8150:3284114] 0.000000~~-62.000000
2017-08-07 17:34:15.398510+0800 JJOC[8150:3284114] <RACTuple: 0x17401b380> (
"<UITableView: 0x10087da00; frame = (0 0; 375 667); clipsToBounds = YES; gestureRecognizers = <NSArray: 0x170249810>; layer = <CALayer: 0x17003d880>; contentOffset: {0, -62.5}; contentSize: {375, 0}>"
)
2017-08-07 17:34:15.398587+0800 JJOC[8150:3284114] 0.000000~~-62.500000
2017-08-07 17:34:15.431838+0800 JJOC[8150:3284114] <RACTuple: 0x17001b3c0> (
"<UITableView: 0x10087da00; frame = (0 0; 375 667); clipsToBounds = YES; gestureRecognizers = <NSArray: 0x170249810>; layer = <CALayer: 0x17003d880>; contentOffset: {0, -63}; contentSize: {375, 0}>"
)
2017-08-07 17:34:15.431922+0800 JJOC[8150:3284114] 0.000000~~-63.000000
2017-08-07 17:34:15.481967+0800 JJOC[8150:3284114] <RACTuple: 0x17401b410> (
"<UITableView: 0x10087da00; frame = (0 0; 375 667); clipsToBounds = YES; gestureRecognizers = <NSArray: 0x170249810>; layer = <CALayer: 0x17003d880>; contentOffset: {0, -63.5}; contentSize: {375, 0}>"
后记
未完,待续~~~