RAC常用的方法,搭配@weakify(self); @weakify(self);
-
- 通知
# RAC中的通知不需要手动remove observer,其内部已经实现
@weakify(self);
[[[NSNotificationCenter defaultCenter] rac_addObserverForName:kNotificationName object:nil]
subscribeNext:^(NSNotification * _Nullable x) {
@strongify(self);
}];
-
- control
# control的通用方法
@weakify(self);
[[button rac_signalForControlEvents:UIControlEventTouchUpOutside] subscribeNext:^(__kindof UIControl * _Nullable x) {
@strongify(self);
}];
# 监听textfild的UIControlEventEditingChanged事件
# 方式一:
[[textFild rac_signalForControlEvents:UIControlEventEditingChanged] subscribeNext:^(__kindof UIControl * _Nullable x){
NSLog(@"change");
}];
# 方式二:
[[self.textFild rac_textSignal] subscribeNext:^(NSString *x) {
NSLog(@"%@",x);
}];
//这样就是每次改变TextFild都输出改变后的结果
-
- Gesturer
# 再比如给我们的某个label添加一个手势动作,我们也可以用简单的RAC代码完成
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] init];
[[tap rac_gestureSignal] subscribeNext:^(__kindof UIGestureRecognizer * _Nullable x) {
NSLog(@"tap");
}];
[self.view addGestureRecognizer:tap];
-
- 代理
用RAC写代理是有局限的,它只能实现返回值为void的代理方法,
RAC为我们提供了一个rac_signalForSelector: fromProtoc:方法帮我们实现代理
# alert方式一:
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"RAC" message:@"RAC TEST" delegate:self cancelButtonTitle:@"cancel" otherButtonTitles:@"other", nil];
[[self rac_signalForSelector:@selector(alertView:clickedButtonAtIndex:) fromProtocol:@protocol(UIAlertViewDelegate)] subscribeNext:^(RACTuple *tuple) {
# tuple封装了方法的参数,可以取出参数对应的值
NSLog(@"%@",tuple.first);
#可以看出tuple.second是点击Item的Index
NSLog(@"%@",tuple.second);
NSLog(@"%@",tuple.third);
}];
[alertView show];
#查看RACTuple
@interface RACTuple : NSObject
@property (nonatomic, readonly) NSUInteger count;
/// These properties all return the object at that index or nil if the number of
/// objects is less than the index.
@property (nonatomic, readonly, nullable) id first;
@property (nonatomic, readonly, nullable) id second;
@property (nonatomic, readonly, nullable) id third;
@property (nonatomic, readonly, nullable) id fourth;
@property (nonatomic, readonly, nullable) id fifth;
@property (nonatomic, readonly, nullable) id last;
2021-03-19 12:24:29.114 RACStudyTest[5003:388870] >
2021-03-19 12:24:29.115 RACStudyTest[5003:388870] 1
2021-03-19 12:24:29.115 RACStudyTest[5003:388870] (null)
# alert方式二
[[alertView rac_buttonClickedSignal] subscribeNext:^(id x) {
# 这里的x是点击Item的Index
NSLog(@"%@",x);
}];
-
- kvo
RAC中得KVO大部分都是宏定义,所以代码异常简洁,简单来说就是 RACObserve(TARGET, KEYPATH)这种形式,TARGET是监听目标,KEYPATH是要观察的属性值
@weakify(self);
[RACObserve(object, propertyChanged) subscribeNext:^(id propertyChangedValue) {
@strongify(self);
}];
[[RACSignal combineLatest:@[RACObserve(self.messageViewController, unReadMessageCount),RACObserve(self.friendsVc, unReadMessageCount),RACObserve(self, unReadSystemCount)]] subscribeNext:^(RACTuple *x) {
@strongify(self);
NSInteger first = ((NSNumber *)x.first).integerValue;
NSInteger second = ((NSNumber *)x.second).integerValue;
NSInteger third = ((NSNumber *)x.third).integerValue;
JHTabBarController *tabbarVC = (JHTabBarController *)self.tabBarController;
[tabbarVC.customTabBar hideBadgeOnItemIndex:3];//隐藏未读小红点
if (first>0||second>0||third>0) {
[tabbarVC.customTabBar showBadgeOnItemIndex:3 value:(first+second+third)];//显示未读小红点
}
}];
RACSignal 封装请求
- (RACSignal *)sendShareMessageWithModel:(JH_ChatRoomBaseModel *)messageModel {
@weakify(self);
return [RACSignal createSignal:^RACDisposable *(id subscriber) {
@strongify(self);
[self addMessageModelToDatabase:messageModel];
//通过Socket向服务器发送消息
[self sendMessageToServerWithModel:messageModel];
// 给订阅者发送消息
[subscriber sendNext:@(YES)];
[subscriber sendCompleted];
return nil;
}];
}
RAC相关类
RACSignal的使用
// 创建一个信号
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id _Nonnull subscriber) {
NSLog(@"创建一个信号");
// 发送信号
[subscriber sendNext:@"发送一个信号"];
return nil;
}];
// 订阅一个信号
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"订阅一个信号");
NSLog(@"订阅到的: %@", x);
}];
2017-07-22 17:37:09.294 RAC[66282:12633516] 创建一个信号
2017-07-22 17:37:09.295 RAC[66282:12633516] 订阅一个信号
2017-07-22 17:37:09.295 RAC[66282:12633516] 订阅到的: 发送一个信号
sendNext就把内容传递到了Next的block中了
UITextField+RACSignalSupport.h
#import
@class RACChannelTerminal;
@class RACSignal<__covariant ValueType>;
NS_ASSUME_NONNULL_BEGIN
#
@interface UITextField (RACSignalSupport)
#
- (RACSignal *)rac_textSignal;
# 用于双向绑定
- (RACChannelTerminal *)rac_newTextChannel;
@end
NS_ASSUME_NONNULL_END
rac_textSignal
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 100, 35)];
textField.center = self.view.center;
textField.backgroundColor = [UIColor yellowColor];
[[textField
rac_textSignal]
subscribeNext:^(NSString * _Nullable x) {
NSLog(@"%@", x);
}];
[self.view addSubview:textField];
2017-07-23 22:55:45.686 RAC[70205:14118946] 1
2017-07-23 22:55:46.139 RAC[70205:14118946] 11
2017-07-23 22:55:46.798 RAC[70205:14118946] 111
rac_newTextChannel
@interface RACChannelTerminal : RACSignal
- (instancetype)init __attribute__((unavailable("Instantiate a RACChannel instead")));
// Redeclaration of the RACSubscriber method. Made in order to specify a generic type.
- (void)sendNext:(nullable ValueType)value;
@end
#rac_newTextChannel效果跟rac_textSignal一样, 那么它有什么特别的用法呢?
[[textField
rac_newTextChannel]
subscribeNext:^(NSString * _Nullable x) {
NSLog(@"%@", x);
}];
#rac_newTextChannel双向绑定
UITextField *textFieldA = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 100, 35)];
textFieldA.center = self.view.center;
textFieldA.backgroundColor = [UIColor yellowColor];
[self.view addSubview:textFieldA];
UITextField *textFieldB = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 100, 35)];
textFieldB.center = CGPointMake(self.view.center.x, self.view.center.y + 50);
textFieldB.backgroundColor = [UIColor yellowColor];
[self.view addSubview:textFieldB];
RACChannelTerminal *terminalA = [textFieldA rac_newTextChannel];
RACChannelTerminal *terminalB = [textFieldB rac_newTextChannel];
[terminalA subscribe:terminalB];
[terminalB subscribe:terminalA];
#运行可以看到, 改变textFieldA的值textFieldB的值也会跟着改变, 反过来也一样.
#这里如果要实现双向绑定, 其实还有一个简单的方法:
RACChannelTo(textFieldA, text) = RACChannelTo(textFieldB, text);
如果我们不仅仅想让两个绑定对象之间的值简单的相等而已呢? 比如textFieldA的值是123的时候textFieldB的值要为321要怎么处理呢?
这里我们先说一个一会用到的方法: map
(映射)
map
方法,将会创建一个和原来一模一样的信号,只不过新的信号传递的值变为了block(value)。
[[[textField
rac_textSignal]
map:^id _Nullable(NSString * _Nullable value) {
if ([value isEqualToString:@"11"]) {
return @"1";
} else {
return @"0";
}
}] subscribeNext:^(id _Nullable x) {
NSLog(@"%@", x);
}];
运行看看, 当我们输入1, 会打印0, 输入11的时候会打印1, 这里就是把传递的值从textField的text转变成为我们的1 和 0;
那么要实现上面的123 到 321可以这样写:
RACChannelTerminal *terminalA = [textFieldA rac_newTextChannel];
RACChannelTerminal *terminalB = [textFieldB rac_newTextChannel];
[[terminalA
map:^id _Nullable(id _Nullable value) {
if ([value isEqualToString:@"123"]) {
return @"321";
}
return value;
}]
subscribe:terminalB];
[terminalB subscribe:terminalA];
大家可以自己运行看看效果, 当textFieldA输入123的时候textFieldB会变为321
RAC(self.sureBtn, enabled) = [RACSignal combineLatest:@[self.phoneTF.rac_textSignal, self.codeTF.rac_textSignal] reduce:^id (NSString *phoneNumber, NSString *code){
@strongify(self);
if (phoneNumber.length==11 && code.length==6) {
self.sureBtn.alpha = 1;
return @(YES);
} else {
self.sureBtn.alpha = 0.6;
return @(NO);
}
}];
UIActionSheet+RACSignalSupport.h
#import
@class RACDelegateProxy;
@class RACSignal<__covariant ValueType>;
NS_ASSUME_NONNULL_BEGIN
@interface UIActionSheet (RACSignalSupport)
@property (nonatomic, strong, readonly) RACDelegateProxy *rac_delegateProxy;
- (RACSignal *)rac_buttonClickedSignal;
@end
rac_buttonClickedSignal
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"RAC ActionSheet" delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:@"OK" otherButtonTitles:@"Other", nil];
[[actionSheet
rac_buttonClickedSignal]
subscribeNext:^(NSNumber * _Nullable x) {
NSLog(@"%@", x);
}];
[actionSheet showInView:self.view];
#运行看看, x是actionSheet上按钮的编号, 我们拿到编号就可以做响应的事件处理了.
UIAlertView+RACSignalSupport.h
@interface UIAlertView (RACSignalSupport)
@property (nonatomic, strong, readonly) RACDelegateProxy *rac_delegateProxy;
- (RACSignal *)rac_buttonClickedSignal;
- (RACSignal *)rac_willDismissSignal;
@end
NS_ASSUME_NONNULL_END
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"RAC" message:@"RAC Alert" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"OK", nil];
[[alert
rac_buttonClickedSignal]
subscribeNext:^(NSNumber * _Nullable x) {
NSLog(@"click: x");
}];
[[alert
rac_willDismissSignal]
subscribeNext:^(NSNumber * _Nullable x) {
NSLog(@"dismiss: %@", x);
}];
[alert show];
UIControl+RACSignalSupport.h
#import
@class RACSignal<__covariant ValueType>;
NS_ASSUME_NONNULL_BEGIN
@interface UIControl (RACSignalSupport)
- (RACSignal<__kindof UIControl *> *)rac_signalForControlEvents:(UIControlEvents)controlEvents;
@end
NS_ASSUME_NONNULL_END
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button setFrame:CGRectMake(0, 0, 100, 35)];
[button setCenter:self.view.center];
[button setBackgroundColor:[UIColor yellowColor]];
[button setTitle:@"按钮" forState:UIControlStateNormal];
[[button
rac_signalForControlEvents:UIControlEventTouchUpInside]
subscribeNext:^(__kindof UIControl * _Nullable x) {
NSLog(@"点击了按钮");
x.backgroundColor = [UIColor redColor];
}];
[self.view addSubview:button];
UIDatePicker+RACSignalSupport.h
#import
@class RACChannelTerminal;
NS_ASSUME_NONNULL_BEGIN
@interface UIDatePicker (RACSignalSupport)
- (RACChannelTerminal *)rac_newDateChannelWithNilValue:(nullable NSDate *)nilValue;
@end
NS_ASSUME_NONNULL_END
UIDatePicker *datePicker = [[UIDatePicker alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 160)];
datePicker.center = self.view.center;
datePicker.backgroundColor = [UIColor redColor];
[self.view addSubview:datePicker];
UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, 180, 35)];
textField.center = CGPointMake(self.view.center.x, self.view.center.y - 100);
textField.backgroundColor = [UIColor yellowColor];
[self.view addSubview:textField];
RACChannelTerminal *datePickerTerminal = [datePicker rac_newDateChannelWithNilValue:[NSDate date]];
RACChannelTerminal *textFieldTerminal = [textField rac_newTextChannel];
[[datePickerTerminal
map:^id _Nullable(id _Nullable value) {
NSLog(@"%@", value);
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
return [dateFormatter stringFromDate:value];
}]
subscribe:textFieldTerminal];