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使用api的方式封装弹窗的示例代码

    React使用api的方式封装弹窗的示例代码

    在现代开发中的弹窗样式,经常会是底部一个叉号样式的弹窗,但是目前组件库中并无类似弹窗组件,本文小编给大家介绍了React使用api的方式封装弹窗的示例,感兴趣的小伙伴跟着小编一起来看看吧
    2024-09-09
  • React组件useReducer的讲解与使用

    React组件useReducer的讲解与使用

    在React函数式组件中,我们可以通过useState()来创建state,这种state创建方式会给我们返回两个东西state和setState()。
    2023-04-04
  • React生命周期方法之componentDidMount的使用

    React生命周期方法之componentDidMount的使用

    这篇文章主要介绍了React生命周期方法之componentDidMount的使用,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-06-06
  • 解决React报错Encountered two children with the same key

    解决React报错Encountered two children with the same key

    这篇文章主要为大家介绍了React报错Encountered two children with the same key解决方法,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • React Native 启动流程详细解析

    React Native 启动流程详细解析

    这篇文章主要介绍了React Native 启动流程简析,文以 react-native-cli 创建的示例工程(安卓部分)为例,给大家分析 React Native 的启动流程,需要的朋友可以参考下
    2021-08-08
  • Native Memory Tracking追踪区域示例分析

    Native Memory Tracking追踪区域示例分析

    这篇文章主要为大家介绍了Native Memory Tracking追踪区域示例分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-11-11
  • 在React 组件中使用Echarts的示例代码

    在React 组件中使用Echarts的示例代码

    本篇文章主要介绍了在React 组件中使用Echarts的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-11-11
  • React中重新实现强制实施表单的流程步骤

    React中重新实现强制实施表单的流程步骤

    这篇文章主要介绍了React中重新实现强制实施表单的流程步骤,就像设计人员一样,在添加逻辑之前,您需要为不同的状态“模拟”或创建“模拟”,例如,这里只是表单的视觉部分的模拟,文中通过代码示例讲解的非常详细,需要的朋友可以参考下
    2024-05-05
  • 解决React报错Property does not exist on type 'JSX.IntrinsicElements'

    解决React报错Property does not exist on 

    这篇文章主要为大家介绍了React报错Property does not exist on type 'JSX.IntrinsicElements'解决方法,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • React中refs的一些常见用法汇总

    React中refs的一些常见用法汇总

    Refs是一个 获取 DOM节点或React元素实例的工具,在React中Refs 提供了一种方式,允许用户访问DOM 节点或者在render方法中创建的React元素,这篇文章主要给大家介绍了关于React中refs的一些常见用法,需要的朋友可以参考下
    2021-07-07

最新评论