iOS中的RAC的使用

本篇內(nèi)容主要記錄一下平時(shí)項(xiàng)目中經(jīng)常會用到的rac的情況斤彼,不做太深入的研究匾鸥。

前言

ReactiveCocoa 可以說是結(jié)合了函數(shù)式編程和響應(yīng)式編程的框架敬拓,也可稱其為函數(shù)響應(yīng)式編程(FRP)框架菜皂,強(qiáng)調(diào)一點(diǎn)棒掠,RAC最大的優(yōu)點(diǎn)是提供了一個(gè)單一的、統(tǒng)一的方法去處理異步的行為立莉,包括delegate方法,blocks回調(diào),target-action機(jī)制,notifications和KVO.

一.導(dǎo)入

1.在項(xiàng)目的podfile文件中添加

  # RAC
  pod 'ReactiveObjC'

2.執(zhí)行pod install方法绢彤,即可導(dǎo)入框架。

3.在使用到rac的類中導(dǎo)入

//響應(yīng)式編程
#import <ReactiveObjC/ReactiveObjC.h>

我的項(xiàng)目中因?yàn)楹芏囝惗紩玫津殉埽灾苯釉趐ch文件導(dǎo)入

二.rac常規(guī)使用

1).button添加點(diǎn)擊事件
比如給一個(gè)登陸按鈕添加點(diǎn)擊事件

    [[self.loginAccountBtn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
        @strongify(self);
        [self.navigationController pushViewController:[[NSClassFromString(@"GHLoginViewController") alloc] init] animated:YES];
    }];

2).替代kvo監(jiān)聽
監(jiān)聽一些屬性的變化茫舶,只要屬性改變就會調(diào)用,并把改變的值傳遞給你刹淌。

//如:
@property(noatomic,assign) int age;
監(jiān)聽age的每一次賦值饶氏,并產(chǎn)生回調(diào)
[RACObserve(self, age) ]subscribeNext:^(id  _Nullable x) {
    NSLog(@"%@",x);
}];
監(jiān)聽age 的賦值,并忽略值為 “1” 的情況有勾,不執(zhí)行回調(diào)
[[RACObserve(self, networkStatus) ignore:@"1"]subscribeNext:^(id  _Nullable x) {
        
}];

//模擬一個(gè)事件  觸摸屏幕 就讓age自增
-(void)touchesBegin:(NSSet<UITouch*>*)touches WithEvent:(UIEvent*)event{
    age++;
}

//在任意類中監(jiān)聽networkStatus值的變化

@interface GHConfigDeviceManager : NSObject
@property (nonatomic) GHNetworkStatus networkStatus;

[[[RACObserve(GHConfigDeviceManager.share, networkStatus) skip:1] distinctUntilChanged] subscribeNext:^(id  _Nullable x) {
        NSLog(@"networkStatus----x=%@",x);
        if ([x intValue] == 2) {
            if (weakself.alertView) {
                [weakself.alertView dismiss:nil];
            }
        }
    }];

3).監(jiān)聽textfeild文字變化

實(shí)時(shí)監(jiān)測輸入文字變化

[[alertView.inputTextField rac_textSignal] subscribeNext:^(NSString * _Nullable x) {
        //昵稱的長度范圍1~20個(gè)字符
        [weakalertView.okBtn setTitleColor:(weakalertView.inputTextField.text.length == 0 || weakalertView.inputTextField.text.length > 20) ? ASColorHex(0xC1CCC9) : ASColorHex(0x0BD087) forState:UIControlStateNormal];
        weakalertView.okBtn.enabled = (x.length == 0 || x.length > 20) ? NO : YES;
    }];

4).監(jiān)聽通知回調(diào)

[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIApplicationDidBecomeActiveNotification object:nil] subscribeNext:^(NSNotification * _Nullable x) {
        NSLog(@"x===%@",x);
}];

5).手勢執(zhí)行方法監(jiān)聽

UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] init];
self.lable.userInteractionEnabled = YES;
[self.lable addGestureRecognizer:tap];
[[tap rac_gestureSignal] subscribeNext:^(__kindof UIGestureRecognizer * _Nullable x) {
        
}];

6).數(shù)組與字典遍歷
數(shù)組遍歷

NSArray *array = @[@"111",@"222",@"333",@"444"];
[array.rac_sequence.signal subscribeNext:^(id  _Nullable x) {
    NSLog(@"x11====%@",x);
}];
2021-05-27 11:22:41.734488+0800 GHome[5071:1101120] x11====222
2021-05-27 11:22:41.734570+0800 GHome[5071:1101120] x11====333
2021-05-27 11:22:41.734634+0800 GHome[5071:1101120] x11====444

字典遍歷

NSDictionary *dict = @{@"111":@"-111",@"222":@"-222",@"333":@"-333",@"444":@"-444"};
    [dict.rac_sequence.signal subscribeNext:^(id  _Nullable x) {
    NSLog(@"x22====%@",x);
}];

以下為打印內(nèi)容疹启,RACTwoTuple可視為二維數(shù)組類型

2021-05-27 11:19:24.804544+0800 GHome[5064:1099660] x22====<RACTwoTuple: 0x2834c09f0> (
    222,
    "-222"
)
2021-05-27 11:19:24.804825+0800 GHome[5064:1099660] x22====<RACTwoTuple: 0x2834c0bb0> (
    111,
    "-111"
)
2021-05-27 11:19:24.804941+0800 GHome[5064:1099660] x22====<RACTwoTuple: 0x2834c0bc0> (
    444,
    "-444"
)
2021-05-27 11:19:24.805051+0800 GHome[5064:1099660] x22====<RACTwoTuple: 0x2834c0be0> (
    333,
    "-333"
)

三 .常用RAC高階函數(shù)
1).信號合并combineLastest

    RACSignal *accountSignal = self.accountTextField.rac_textSignal;
    RACSignal *passwordSignal = self.passwordTextField.rac_textSignal;

    RAC(self, loginBtn.enabled) = [RACSignal combineLatest:@[accountSignal, passwordSignal] reduce:^id(NSString *account, NSString *password){
        @strongify(self);
        BOOL b;
        b = [account isValidatePhoneNumber];
        return @(b && [password isValidatePassword]);
    }];

account為accountSignal信號的回調(diào)值,password為passwordSignal信號的回調(diào)值蔼卡,我們在reduce回調(diào)函數(shù)里面處理?xiàng)l件判斷喊崖,并將判斷結(jié)果以信號的形式返回給loginBtn.enabled的值

2).map的使用
一句話概括map的作用:主要用于數(shù)據(jù)的再封裝與改造
例1 監(jiān)聽code_version的值變化,并字符串格式化雇逞,最后賦值到accessoryTitle屬性

RAC(self, accessoryTitle) = [RACObserve(self, deviceViewModel.code_version)  map:^id _Nullable(NSString *_Nullable value) {
        return ASStringFormat(@"V%@", value);
}];

例2 遍歷value數(shù)組并將value中元素重新組裝生成GHDeviceSettingModel值荤懂,然后重新生成數(shù)組array返回

[value.rac_sequence map:^GHDeviceSettingViewModel * _Nullable(NSDictionary *_Nullable value) {
        @strongify(self);
        GHDeviceSettingModel *model = [GHDeviceSettingModel mj_objectWithKeyValues:value];
        return [[GHDeviceSettingViewModel alloc] initWithSettingModel:model deviceViewModel:self.deviceViewModel];
}].array

3). filter的使用
例1 只有在textfeild輸入框中的內(nèi)容少于六位的時(shí)候執(zhí)行回調(diào)

self.textField.rac_textSignal filter: BOOL (NSString *_ Nullable value) {
    if (self.textField.text.length>6) f
    self.textField.text = [self.textField.text substringToIndex:6];
}
    return value.length<6;
}] subscribeNext:(NSString *_ Nullable x){
    NSLog(@"filter----%@",x);
];

filter經(jīng)常情況伴隨著sequence(遍歷)一起使用
例2
遍歷數(shù)組dataSource的值,根據(jù)需求添加過濾條件喝峦,當(dāng)return YES時(shí)會添加到返回的數(shù)組array中势誊,return NO時(shí)不會添加到數(shù)組array中

NSArray *tempArray = [[self.OTAViewModel.dataSource rac_sequence] filter:^BOOL(GHOTACellViewModel* _Nullable value) {
    if (value.type.intValue == 2) {
            return YES;
    }
    return NO;
}].array;

使用rac進(jìn)行遍歷的好處就是,遍歷過程中不用重新創(chuàng)建Array或Dictionary谣蠢,即可拿到新生成的Array或Dictionary

4).flattenMap 映射
例 對輸入內(nèi)容進(jìn)行二次封裝處理

[[self.textField.rac_textSignal flattenMap:__kindof RACSignal *_ Nullable(NSString *
_Nullable value) {
    NSLog( @"%@",value);//+8610086
    return [RACReturnSignal return:[NSString stringWithFormat:@"+86%@",value]];
}] subscribeNext:^(id _Nullable х) {
    NSLog(@"映射: %@",x);
}];

三.結(jié)合MVVM+RAC的簡單使用
這里簡單介紹一下mvvm
眾所周知MVC模式具有厚重的ViewController粟耻、遺失的網(wǎng)絡(luò)邏輯(沒有屬于它的位置)查近、較差的可測試性等問題。因此也就會有維護(hù)性較強(qiáng)挤忙、耦合性很低的一種新架構(gòu)MVVM (MVC 引申出得新的架構(gòu))的流行霜威。

圖片.png

主要在于 ViewModel
ViewModel: 相比較于MVC新引入的視圖模型。是視圖顯示邏輯册烈、驗(yàn)證邏輯戈泼、網(wǎng)絡(luò)請求等代碼存放的地方,唯一要注意的是赏僧,任何視圖本身的引用都不應(yīng)該放在VM中大猛,換句話說就是VM中不要引入U(xiǎn)IKit.h (對于image這個(gè),也有人將其看做數(shù)據(jù)來處理淀零,這就看個(gè)人想法了挽绩,并不影響整體的架構(gòu))。

比如一個(gè)用戶登錄網(wǎng)絡(luò)請求,將網(wǎng)絡(luò)請求相關(guān)邏輯都放到viewModel中執(zhí)行

@interface GHLoginViewModel : NSObject

@property (nonatomic, strong) RACCommand *loginCommand;

@property (nonatomic, strong) RACCommand *refreshTokenCommand;


@interface GHLoginRequest : GHNetworkBaseRequest

/// 手機(jī)號\郵箱
@property (nonatomic, copy) NSString *username;

/// 密碼(密碼由 8 - 128 字符組成驾中,不能為純數(shù)字或字母)
@property (nonatomic, copy) NSString *password;

/// 國家碼簡稱
@property (nonatomic, copy) NSString *region_code;

/// 手機(jī)號國家碼
@property (nonatomic, copy) NSNumber *phone_code;

@end

@implementation GHLoginViewModel

- (instancetype)init
{
    self = [super init];
    if (self) {
    }
    return self;
}

- (RACCommand *)loginCommand {
    if (!_loginCommand) {
        _loginCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal * _Nonnull(GHLoginRequest* _Nullable input) {
            return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
                NSString *taskId = [GHNetworkModule.share sendRequest:input cacheComplete:nil networkComplete:^(GHNetworkResponse *response) {
                    if (response.status == GHNetworkResponseStatusSuccess) {
                        GHUserInfo.share.password = input.password;
                        GHUserInfo.share.token = response.data[@"token"];
                        [subscriber sendNext:response.data];
                        [subscriber sendCompleted];
                        [GHUserInfo cacheInfo];
                    } else {
                        [subscriber sendError:response.error];
                    }
                }];
                return [RACDisposable disposableWithBlock:^{
                    [GHNetworkModule.share cancelRequestWithRequestID:taskId];
                }];
            }];
        }];
    }
    return _loginCommand;
}

在viewcontoller中接收請求結(jié)果

    //返回?cái)?shù)據(jù)處理
    [self.viewModel.loginCommand.executionSignals.switchToLatest subscribeNext:^(id  _Nullable x) {
        @strongify(self)
        [GHHudTip hideHUDWithView:self.view];
    }];
    
    //異常處理
    [self.viewModel.loginCommand.errors subscribeNext:^(NSError * _Nullable x) {
        @strongify(self)
        [GHHudTip hideHUDWithView:self.view];
        [GHHudTip showTips:x.domain];
    }];
    

延伸與擴(kuò)展:iOS MVVM+RAC 從框架到實(shí)戰(zhàn)

結(jié)語:RAC的功能非常強(qiáng)大唉堪,且實(shí)用。這里只是列舉了一小部分肩民。其他還需要我們在開發(fā)中慢慢發(fā)掘唠亚。加油~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市持痰,隨后出現(xiàn)的幾起案子灶搜,更是在濱河造成了極大的恐慌,老刑警劉巖共啃,帶你破解...
    沈念sama閱讀 222,681評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件占调,死亡現(xiàn)場離奇詭異,居然都是意外死亡移剪,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,205評論 3 399
  • 文/潘曉璐 我一進(jìn)店門薪者,熙熙樓的掌柜王于貴愁眉苦臉地迎上來纵苛,“玉大人,你說我怎么就攤上這事言津」ト耍” “怎么了?”我有些...
    開封第一講書人閱讀 169,421評論 0 362
  • 文/不壞的土叔 我叫張陵悬槽,是天一觀的道長怀吻。 經(jīng)常有香客問我,道長初婆,這世上最難降的妖魔是什么蓬坡? 我笑而不...
    開封第一講書人閱讀 60,114評論 1 300
  • 正文 為了忘掉前任猿棉,我火速辦了婚禮,結(jié)果婚禮上屑咳,老公的妹妹穿的比我還像新娘萨赁。我一直安慰自己,他們只是感情好兆龙,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,116評論 6 398
  • 文/花漫 我一把揭開白布杖爽。 她就那樣靜靜地躺著,像睡著了一般紫皇。 火紅的嫁衣襯著肌膚如雪慰安。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,713評論 1 312
  • 那天聪铺,我揣著相機(jī)與錄音泻帮,去河邊找鬼。 笑死计寇,一個(gè)胖子當(dāng)著我的面吹牛锣杂,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播番宁,決...
    沈念sama閱讀 41,170評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼元莫,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蝶押?” 一聲冷哼從身側(cè)響起踱蠢,我...
    開封第一講書人閱讀 40,116評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎棋电,沒想到半個(gè)月后茎截,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,651評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡赶盔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,714評論 3 342
  • 正文 我和宋清朗相戀三年企锌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片于未。...
    茶點(diǎn)故事閱讀 40,865評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡撕攒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出烘浦,到底是詐尸還是另有隱情抖坪,我是刑警寧澤,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布闷叉,位于F島的核電站擦俐,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏握侧。R本人自食惡果不足惜蚯瞧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,211評論 3 336
  • 文/蒙蒙 一嘿期、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧状知,春花似錦秽五、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,699評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至西设,卻和暖如春瓣铣,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背贷揽。 一陣腳步聲響...
    開封第一講書人閱讀 33,814評論 1 274
  • 我被黑心中介騙來泰國打工棠笑, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人禽绪。 一個(gè)月前我還...
    沈念sama閱讀 49,299評論 3 379
  • 正文 我出身青樓蓖救,卻偏偏與公主長得像,于是被迫代替她去往敵國和親印屁。 傳聞我的和親對象是個(gè)殘疾皇子循捺,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,870評論 2 361

推薦閱讀更多精彩內(nèi)容

  • 夜鶯2517閱讀 127,728評論 1 9
  • 版本:ios 1.2.1 亮點(diǎn): 1.app角標(biāo)可以實(shí)時(shí)更新天氣溫度或選擇空氣質(zhì)量,建議處女座就不要選了雄人,不然老想...
    我就是沉沉閱讀 6,908評論 1 6
  • 我是一名過去式的高三狗从橘,很可悲,在這三年里我沒有戀愛础钠,看著同齡的小伙伴們一對兒一對兒的恰力,我的心不好受。怎么說呢旗吁,高...
    小娘紙閱讀 3,393評論 4 7
  • 這些日子就像是一天一天在倒計(jì)時(shí) 一想到他走了 心里就是說不出的滋味 從幾個(gè)月前認(rèn)識他開始 就意識到終究會發(fā)生的 只...
    栗子a閱讀 1,624評論 1 3