ReactiveCocoa代码实践之-UI组件的RAC信号操作

 更新时间:2016年04月20日 10:02:47   作者:董铂然  
这篇文章主要介绍了ReactiveCocoa代码实践之-UI组件的RAC信号操作 的相关资料,需要的朋友可以参考下

相关阅读:

ReactiveCocoa代码实践之-更多思考

ReactiveCocoa代码实践之-RAC网络请求重构这一节是自己对网络层的一些重构,本节是自己一些代码小实践做出的一些demo程序,基本涵盖大多数UI控件操作。

一.用UISlider实现调色板

假设我们现在做一个demo,上面有一个View用来展示颜色,下面有三个UISlider滑竿分别控制RGB的色值,随着不同滑竿的拖动上面view的颜色会随之改变。 可以先脑补一下不用RAC该怎么写。 如果使用RAC只需要将三个信号包装起来用适当的操作就能实现。

// 拖线的UI控件
@property (weak, nonatomic) IBOutlet UIView *topView;
@property (weak, nonatomic) IBOutlet UISlider *slider;
@property (weak, nonatomic) IBOutlet UISlider *slider;
@property (weak, nonatomic) IBOutlet UISlider *slider;
// viewDidLoad中
// 分别将三个控件的改变都包成一个信号。
RACSignal *s = [[self.slider rac_newValueChannelWithNilValue:@]startWith:@];
RACSignal *s = [[self.slider rac_newValueChannelWithNilValue:@]startWith:@];
RACSignal *s = [[self.slider rac_newValueChannelWithNilValue:@]startWith:@];
RACSignal *threeSignal = [RACSignal combineLatest:@[s,s,s] reduce:^id(NSNumber* value,NSNumber* value,NSNumber* value){
return @[value,value,value];
}];
// 监听这个"合成"后的信号,改变view的颜色
[threeSignal subscribeNext:^(NSArray *arr) {
self.topView.backgroundColor = [UIColor colorWithRed:[arr[] doubleValue] green:[arr[] doubleValue] blue:[arr[] doubleValue] alpha:];
}]; 

上面的startWith:@0需要注意,如果不加这个初始值那必须在三个滑竿都动一下才能显示颜色。 上面使用的方法时UISlider专属的,也可以用下面的方法写,这个是UIControl的方法会支持更多其他UI控件。

RACSignal *s1 = [[[self.slider1 rac_signalForControlEvents:UIControlEventValueChanged] map:^id(id value) {
return @(self.slider1.value);
}] startWith:@0];

二.简洁代码实现登录逻辑

在UI控件中难点不多,但是值得注意的就是各种状态的多级管理,如果哪里疏忽了就很容易造成bug,这也就导致很多地方有判断结构,并且各种来回赋值。 假设现在需要做一个登录框,有账号密码和同意条款三项,必须满足账号密码大于2位且选择了同意,才允许注册。 旧的写法非常麻烦,还需要监听valueChange事件等。如果用RAC只需要写如下代码:

@property (weak, nonatomic) IBOutlet UITextField *accountTxt;
@property (weak, nonatomic) IBOutlet UITextField *pwdTxt;
@property (weak, nonatomic) IBOutlet SXSwitch *agreeSw; // 同意条款
@property (weak, nonatomic) IBOutlet UIButton *loginBtn; // 注册按钮
// viewDidLoad方法
self.loginBtn.enabled = NO;
RAC(self.loginBtn , enabled) = [RACSignal combineLatest:@[self.accountTxt.rac_textSignal , self.pwdTxt.rac_textSignal, self.agreeSw.rac_newOnChannel] reduce:^(NSString *account, NSString *pwd, NSNumber *isOn){
return @((account.length > )&&(pwd.length >)&&[isOn boolValue]);
}]; 

这其中combineLatest数组中用的都是控件专属的信号, 也可以使用RAC(self.agreeSw, on) 这种写法直接把某一个属性的状态用信号传过来。但是这里需要注意:假设你监听了A类的B属性时,只有走了B属性的set方法才会被监听捕获,如果是通过其他方法修改的属性值则无效。 比如UISwitch的来回拨动过程中并没有走on这个属性的set方法。

三.通过interval方法实现时钟

这是一种默认循环的方法,除非你通过控制Disposable把他禁了。 interval这个方法就是传入一个参数是间隔时间,然后内部每隔这一段时间就发一个[NSDate date]的对象,然后block内部把这个date设置一个格式以字符串的方法返回。

RAC(self, timeLabel.text) = [[[RACSignal interval: onScheduler:[RACScheduler currentScheduler]] startWith:[NSDate date]] map:^id (NSDate *value) {
NSDateComponents *dateComponents = [[NSCalendar currentCalendar] components:NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond fromDate:value];
return [NSString stringWithFormat:@"%ld:%ld:%ld", (long)dateComponents.hour, (long)dateComponents.minute, (long)dateComponents.second];
}];

四.其他控件事件操作

除了上面的UIButton,UISlider,UIControl的分类方法还有很多操作

UISegmentedControl (RACSignalSupport)分类就为此控件提供了便捷处理方法,相比于常规的监听seg的元素点击事件,再取出当前选中的index。RACSignal可以直接得到需要的值

[[self.seg rac_newSelectedSegmentIndexChannelWithNilValue:@]subscribeNext:^(id x) {
// 返回的基本数据类型都被装包成NSNumber,可在此做一些判断操作
NSLog(@"selectIndex-%@",x);
}];

UIDatePicker (RACSignalSupport)分类为时间选择框封装了一个操作,每当选框改变时返回NSDate类型

[[picker rac_newDateChannelWithNilValue:[NSDate date]]subscribeNext:^(NSDate *x) {
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = @"HH:mm";
dateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"zh_CN"];
NSString *dateStr = [dateFormatter stringFromDate:x];
}]; 

如果在这里给控件赋值,每一次改动都会让展示控件的值更新,如果有的设计不希望这么频繁只有在点击确认后再将时间显示可以根据自己喜好自行赋值。

除此这些还有很多UI控件绑定的方法 UIAlertView (RACSignalSupport) 里面就提供了一些方法比如点击弹窗按钮可以在subscribeNext里统一处理各个按钮的点击事件。 但是现在UIAlertView已被UIAlertController取代所以,UIAlertView和UIActionSheet这里可以忽略不提。

五.生命周期相关操作

UITableView和UICollectionView的Cell都有重用的机制,如果给这个Cell绑定了一些监听,那这个Cell被重用它子控件的监听该何去何从?UITableViewCell (RACSignalSupport)、UICollectionReusableView (RACSignalSupport)这两个分类里提供了即将重用时的信号rac_prepareForReuseSignal

做过两个类似的场景,一个是tableView的cell回复按钮点击会跳到回复页,一个是collection的item内有个按钮点击就变颜色。

// UITableViewDataSource
- (UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath {
SXFeedbackCell * cell = [tableView dequeueReusableCellWithIdentifier:@"SXFeedbackCell"];
@weakify(self)
[[[cell.replyButton rac_signalForControlEvents:UIControlEventTouchUpInside] takeUntil:cell.rac_prepareForReuseSignal]
subscribeNext:^(UIButton *x) {
@strongify(self)
// 处理一些其他逻辑
[self.navigationController pushViewController:[SXReplyPage new] animated:YES];
}];
return cell;
}
// UICollectionViewDataSource
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell * cell = [collectionView dequeueReusableCellWithIdentifier:@"SXDownloadCell"];
[[[cell.changeBtn rac_signalForControlEvents:UIControlEventTouchUpInside] takeUntil:cell.rac_prepareForReuseSignal]
subscribeNext:^(UIButton *x) {
cell.backgroundColor = [UIColor grayColor];
}];
return cell;
}

其中takeUntil操作是监听某个事件直到什么时候结束。当这个cell即将重用时rac_prepareForReuseSignal到来会触发disposable信号结束监听。

非重用类型的控件的生命周期可以用rac_willDeallocSignal 信号监听,但是在开发中很少会用到此信号,因为大多是信号操作的内部代码里都帮你做了这个操作,即监听一个事件直到自己结束时停止监听。

// rac_textSignal源码
- (RACSignal *)rac_textSignal {
@weakify(self);
return [[[[[RACSignal
defer:^{
@strongify(self);
return [RACSignal return:self];
}]
concat:[self rac_signalForControlEvents:UIControlEventAllEditingEvents]]
map:^(UITextField *x) {
return x.text;
}]
takeUntil:self.rac_willDeallocSignal]
setNameWithFormat:@"%@ -rac_textSignal", self.rac_description];
}
// rac_signalForControlEvents源码
- (RACSignal *)rac_signalForControlEvents:(UIControlEvents)controlEvents {
@weakify(self);
return [[RACSignal
createSignal:^(id<RACSubscriber> subscriber) {
@strongify(self);
[self addTarget:subscriber action:@selector(sendNext:) forControlEvents:controlEvents];
[self.rac_deallocDisposable addDisposable:[RACDisposable disposableWithBlock:^{
[subscriber sendCompleted];
}]];
return [RACDisposable disposableWithBlock:^{
@strongify(self);
[self removeTarget:subscriber action:@selector(sendNext:) forControlEvents:controlEvents];
}];
}]
setNameWithFormat:@"%@ -rac_signalForControlEvents: %lx", self.rac_description, (unsigned long)controlEvents];
}

关于ReactiveCocoa代码实践之-UI组件的RAC信号操作就给大家介绍这么多,希望对大家有所帮助!

相关文章

  • 深入理解React State 原理

    深入理解React State 原理

    本文主要介绍了React State 原理,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • 使用Axios在React中请求数据的方法详解

    使用Axios在React中请求数据的方法详解

    这篇文章主要给大家介绍了初学React,如何规范的在react中请求数据,主要介绍了使用axios进行简单的数据获取,加入状态变量,优化交互体验,自定义hook进行数据获取和使用useReducer改造请求,本文主要适合于刚接触React的初学者以及不知道如何规范的在React中获取数据的人
    2023-09-09
  • 深入了解响应式React Native Echarts组件

    深入了解响应式React Native Echarts组件

    近年来,随着移动端对数据可视化的要求越来越高,通过 WebView 在移动端使用 Echarts 这样功能强大的前端数据可视化库,是解决问题的好办法。下面就和小编来一起学习一下吧
    2019-05-05
  • React事件处理超详细介绍

    React事件处理超详细介绍

    这篇文章主要介绍了React事件处理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-09-09
  • React Native 使用Fetch发送网络请求的示例代码

    React Native 使用Fetch发送网络请求的示例代码

    本篇文章主要介绍了React Native 使用Fetch发送网络请求的示例代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-12-12
  • React中使用Vditor自定义图片详解

    React中使用Vditor自定义图片详解

    这篇文章主要介绍了React中使用Vditor自定义图片详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12
  • React中useCallback useMemo到底该怎么用

    React中useCallback useMemo到底该怎么用

    在React函数组件中,当组件中的props发生变化时,默认情况下整个组件都会重新渲染。换句话说,如果组件中的任何值更新,整个组件将重新渲染,包括没有更改values/props的函数/组件。在react中,我们可以通过memo,useMemo以及useCallback来防止子组件的rerender
    2023-02-02
  • 浅谈React前后端同构防止重复渲染

    浅谈React前后端同构防止重复渲染

    这篇文章主要介绍了浅谈React前后端同构防止重复渲染,首先解释React前后端同构、React首屏渲染的概念。然后通过这2个概念解决服务端渲染完成后浏览器端重复渲染的问题。有兴趣的可以了解一下
    2018-01-01
  • React中useState的使用方法及注意事项

    React中useState的使用方法及注意事项

    useState通过在函数组件里调用它来给组件添加一些内部state,下面这篇文章主要给大家介绍了关于React中useState的使用方法及注意事项的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-08-08
  • React-Hook中使用useEffect清除定时器的实现方法

    React-Hook中使用useEffect清除定时器的实现方法

    这篇文章主要介绍了React-Hook中useEffect详解(使用useEffect清除定时器),主要介绍了useEffect的功能以及使用方法,还有如何使用他清除定时器,需要的朋友可以参考下
    2022-11-11

最新评论