iOS 技巧很常

RAC整理

2021-03-30  本文已影响0人  Xl_Lee

RAC常用的方法,搭配@weakify(self); @weakify(self);

# RAC中的通知不需要手动remove observer,其内部已经实现
  @weakify(self);
 [[[NSNotificationCenter defaultCenter] rac_addObserverForName:kNotificationName object:nil] 
  subscribeNext:^(NSNotification * _Nullable x) {
        @strongify(self);

    }];

# 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都输出改变后的结果
# 再比如给我们的某个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 <NSCoding, NSCopying, NSFastEnumeration>

@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] <UIAlertView: 0x7ff260c90c70; frame = (0 0; 0 0); layer = <CALayer: 0x7ff260c91030>>
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);
}];

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<RACSubscriber> 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<RACSubscriber>  _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 <UIKit/UIKit.h>

@class RACChannelTerminal<ValueType>;
@class RACSignal<__covariant ValueType>;

NS_ASSUME_NONNULL_BEGIN
# 
@interface UITextField (RACSignalSupport)
#  
- (RACSignal<NSString *> *)rac_textSignal;
# 用于双向绑定
- (RACChannelTerminal<NSString *> *)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<ValueType> : RACSignal<ValueType> <RACSubscriber>

- (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 <UIKit/UIKit.h>

@class RACDelegateProxy;
@class RACSignal<__covariant ValueType>;

NS_ASSUME_NONNULL_BEGIN

@interface UIActionSheet (RACSignalSupport)

@property (nonatomic, strong, readonly) RACDelegateProxy *rac_delegateProxy;

- (RACSignal<NSNumber *> *)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<NSNumber *> *)rac_buttonClickedSignal;


- (RACSignal<NSNumber *> *)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 <UIKit/UIKit.h>

@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 <UIKit/UIKit.h>

@class RACChannelTerminal<ValueType>;

NS_ASSUME_NONNULL_BEGIN

@interface UIDatePicker (RACSignalSupport)

- (RACChannelTerminal<NSDate *> *)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];
截屏2021-03-19 下午2.46.31.png
上一篇下一篇

猜你喜欢

热点阅读