ReactiveCocoa+MVVM
主要介紹ReactiveCocoa的使用(適合入門(mén)選手查看)藐吮,對(duì)于新手來(lái)說(shuō)器虾,先會(huì)用朵锣,然后慢慢推敲原理捞高,理解加靈活運(yùn)用氯材。本文借鑒了這篇不錯(cuò)的文章:最快上手ReactiveCocoa引用了部分注釋和說(shuō)明
前言
說(shuō)起MVC架構(gòu)大家都比較熟悉,也是使用很難廣硝岗,但是MVVM這個(gè)項(xiàng)目架構(gòu)氢哮,搭配函數(shù)響應(yīng)式的編程,會(huì)變得更加如魚(yú)得水型檀,寫(xiě)出的項(xiàng)目也是很具特點(diǎn)冗尤,符合高內(nèi)聚,低耦合
的思想胀溺。本博客將主要通過(guò)Github:FanRACExtensions項(xiàng)目來(lái)練習(xí)MVVM框架的ReactiveCocoa響應(yīng)式編程裂七,并且給出一些RAC的擴(kuò)展。
1.ReactiveCocoa+MVVM簡(jiǎn)介
1.1ReactiveCocoa簡(jiǎn)介
ReactiveCocoa(簡(jiǎn)稱(chēng)為RAC),是Github上開(kāi)源的一個(gè)iOS和OS平臺(tái)新框架,該項(xiàng)目是函數(shù)響應(yīng)式編程仓坞,借助大量KVO背零,KVC的綁定,這種設(shè)計(jì)思路代碼可觀性強(qiáng)无埃,目前GitHub上有很多這種成熟框架捉兴。
- ReactiveCocoa — 被重寫(xiě)swift版本。
- ReactiveSwift — 純swift版本录语。
- ReactiveObjCBridge — OC橋接版本倍啥。
- ReactiveObjC — 純Object-C版本。
1.2什么是MVVM?
MVVM想對(duì)應(yīng)于MVC澎埠,實(shí)質(zhì)上沒(méi)有本質(zhì)區(qū)別虽缕,但是MVVM比MVC架構(gòu)中多了一個(gè)ViewModel,就是這個(gè)ViewModel蒲稳,卻是MVVM相對(duì)于MVC改進(jìn)的核心思想氮趋。在開(kāi)發(fā)過(guò)程中伍派,由于需求的變更或添加,項(xiàng)目的復(fù)雜度越來(lái)越高剩胁,代碼量越來(lái)越大诉植,此時(shí)我們會(huì)發(fā)現(xiàn)MVC維護(hù)起來(lái)有些吃力,所以有人想到把Controller的數(shù)據(jù)和邏輯處理部分從中抽離出來(lái)昵观,用一個(gè)專(zhuān)門(mén)的對(duì)象去管理晾腔,這個(gè)對(duì)象就是ViewModel,是Model和Controller之間的一座橋梁啊犬。這樣Controller中的代碼變得非常少灼擂,變得易于測(cè)試和維護(hù),只需要Controller和ViewModel做數(shù)據(jù)綁定即可觉至,可是在實(shí)際使用過(guò)程中剔应,MVVM寫(xiě)出的代碼量并不比MVC的少,有時(shí)反而還會(huì)多點(diǎn)语御,畢竟多了一個(gè)數(shù)據(jù)綁定過(guò)程峻贮,但邏輯會(huì)清晰很多,對(duì)于多人開(kāi)發(fā)的團(tuán)隊(duì)应闯。
2.ReactiveCocoa使用和說(shuō)明
學(xué)習(xí)ReactiveCocoa之前月洛,首先要搞懂幾個(gè)常用的類(lèi)RACSiganl
,RACSubscriber
,RACDisposable
,RACCommand
等下面我們一一介紹
2.1 RACSiganl創(chuàng)建于與使用
RACSignal的核心就是,創(chuàng)建信號(hào)createSignal
,發(fā)送信號(hào)sendNext
,完成信號(hào)sendCompleted
孽锥,和銷(xiāo)毀信號(hào)[RACDisposable disposableWithBlock:^{ }];
,訂閱信號(hào)subscribeNext
.
//信號(hào)量創(chuàng)建
RACSignal *siganl=[[[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
sleep(2);
//sendNext通過(guò)信號(hào)量發(fā)送值嚼黔,傳值(可以是異步)訂閱后能接受該值
[subscriber sendNext:@{@"userName":"username",@"password":"123456"}];
//報(bào)告信息執(zhí)行完成,類(lèi)似于回調(diào)完成一樣
[subscriber sendCompleted];
return [RACDisposable disposableWithBlock:^{
//block調(diào)用時(shí)刻:當(dāng)信號(hào)發(fā)送完成或者發(fā)送錯(cuò)誤惜辑,就會(huì)自動(dòng)執(zhí)行這個(gè)block,取消訂閱信號(hào)唬涧。
}];
}]map:^id _Nullable(id _Nullable value) {
return value;
}] logError] replayLazily];
// 訂閱信號(hào),才會(huì)激活信號(hào),只有發(fā)送了sendNext方法才會(huì)調(diào)用該訂閱方法
[siganl subscribeNext:^(id x) {
// block調(diào)用時(shí)刻:每當(dāng)有信號(hào)發(fā)出數(shù)據(jù),就會(huì)調(diào)用block.
NSLog(@"接收到數(shù)據(jù):%@",x);
}];
RACSubscriber
:表示訂閱者的意思盛撑,用于發(fā)送信號(hào)碎节,這是一個(gè)協(xié)議,不是一個(gè)類(lèi)抵卫,只要遵守這個(gè)協(xié)議狮荔,并且實(shí)現(xiàn)方法才能成為訂閱者。通過(guò)create創(chuàng)建的信號(hào)介粘,都有一個(gè)訂閱者殖氏,幫助他發(fā)送數(shù)據(jù)。RACDisposable
:用于取消訂閱或者清理資源姻采,當(dāng)信號(hào)發(fā)送完成或者發(fā)送錯(cuò)誤的時(shí)候雅采,就會(huì)自動(dòng)觸發(fā)它。在使用中如果不想監(jiān)聽(tīng)某個(gè)信號(hào)時(shí),可以通過(guò)它主動(dòng)取消訂閱信號(hào)婚瓜。RACSubject
:信號(hào)提供者宝鼓,自己可以充當(dāng)信號(hào),又能發(fā)送信號(hào),可以充當(dāng)代理巴刻。RACTuple
和RACTupleUnpack
類(lèi)似于數(shù)組愚铡,元組,集合胡陪,可以處理信號(hào)返回的數(shù)據(jù)
2.2 RACSiganl其他方法及含義
因?yàn)镽AC封裝的原理是沥寥,一切皆信號(hào),所以信號(hào)的其他方法也可以一并了解下
//map數(shù)據(jù)整合(純數(shù)據(jù))督弓,flattenMap數(shù)據(jù)過(guò)濾(內(nèi)部返回的是信號(hào))
[single map:^id _Nullable(RACTuple * value) {
//這里可以過(guò)濾數(shù)據(jù)(RACTuple表示返回?cái)?shù)據(jù)元組)
RACTupleUnpack(id response,id responseObject)=value;
//本來(lái)兩個(gè)參數(shù)返回营曼,傳給下一層就一個(gè)參數(shù)
return responseObject;
}]flattenMap:^__kindof RACSignal * _Nullable(id _Nullable value) {
//過(guò)濾錯(cuò)誤數(shù)據(jù)
if ([value isKindOfClass:[NSError class]]) {
return [RACSignal error:value];
}
return [RACSignal return:value];
}]
-
map
純數(shù)據(jù)組合,返回?cái)?shù)據(jù) -
filter
數(shù)據(jù)過(guò)濾乒验,返回@(YES)or @(NO) -
flattenMap
過(guò)濾和返回?cái)?shù)據(jù)信號(hào)量愚隧,錯(cuò)誤信號(hào)和完成信號(hào) -
ignore
忽略掉什么樣的數(shù)據(jù)一般配合filter使用 -
skip
一般訂閱消息,會(huì)默認(rèn)執(zhí)行一次初始化的操作锻全,[single skip:1]
跳過(guò)第一次 -
merge
合并兩個(gè)信號(hào)到一個(gè)信號(hào)上
3.RACCommand使用和說(shuō)明
學(xué)習(xí)RACCommand之前狂塘,我們通過(guò)我這個(gè)例子簡(jiǎn)單來(lái)說(shuō),就是登錄用戶(hù)名和密碼鳄厌,這里面就用到了ViewModel了荞胡,即數(shù)據(jù)的綁定。首先我要知道幾個(gè)概念或者宏了嚎。
-
@weakify(self);
=類(lèi)似于弱引用 泪漂,@strongify(self);
=強(qiáng)引用,一般放block塊里面歪泳; -
RAC(<#TARGET, ...#>)
用來(lái)綁定UI的文本或?qū)傩灾档絭iewModel里面對(duì)應(yīng)的屬性上(可以理解成KVC綁定)萝勤; -
RACObserve(TARGET, KEYPATH)
訂閱一個(gè)值信號(hào),可以在viewmodel也可在VC里(可以理解成KVO監(jiān)聽(tīng))呐伞;
3.1 使用步驟:
// 一敌卓、RACCommand使用步驟:
// 1.創(chuàng)建命令 initWithSignalBlock:(RACSignal * (^)(id input))signalBlock
// 2.在signalBlock中,創(chuàng)建RACSignal伶氢,并且作為signalBlock的返回值
// 3.執(zhí)行命令 - (RACSignal *)execute:(id)input
// 二趟径、RACCommand使用注意:
// 1.signalBlock必須要返回一個(gè)信號(hào),不能傳nil.
// 2.如果不想要傳遞信號(hào)癣防,直接創(chuàng)建空的信號(hào)[RACSignal empty];
// 3.RACCommand中信號(hào)如果數(shù)據(jù)傳遞完蜗巧,必須調(diào)用[subscriber sendCompleted],這時(shí)命令才會(huì)執(zhí)行完畢蕾盯,否則永遠(yuǎn)處于執(zhí)行中惧蛹。
// 4.RACCommand需要被強(qiáng)引用,否則接收不到RACCommand中的信號(hào),因此RACCommand中的信號(hào)是延遲發(fā)送的香嗓。
// 三迅腔、RACCommand設(shè)計(jì)思想:內(nèi)部signalBlock為什么要返回一個(gè)信號(hào),這個(gè)信號(hào)有什么用靠娱。
// 1.在RAC開(kāi)發(fā)中沧烈,通常會(huì)把網(wǎng)絡(luò)請(qǐng)求封裝到RACCommand,直接執(zhí)行某個(gè)RACCommand就能發(fā)送請(qǐng)求像云。
// 2.當(dāng)RACCommand內(nèi)部請(qǐng)求到數(shù)據(jù)的時(shí)候锌雀,需要把請(qǐng)求的數(shù)據(jù)傳遞給外界,這時(shí)候就需要通過(guò)signalBlock返回的信號(hào)傳遞了迅诬。
// 四腋逆、如何拿到RACCommand中返回信號(hào)發(fā)出的數(shù)據(jù)。
// 1.RACCommand有個(gè)執(zhí)行信號(hào)源executionSignals侈贷,這個(gè)是signal of signals(信號(hào)的信號(hào)),意思是信號(hào)發(fā)出的數(shù)據(jù)是信號(hào)惩歉,不是普通的類(lèi)型。
// 2.訂閱executionSignals就能拿到RACCommand中返回的信號(hào)俏蛮,然后訂閱signalBlock返回的信號(hào)撑蚌,就能獲取發(fā)出的值。
// 3.還可以訂閱errors信號(hào)搏屑,和executing信號(hào)争涌,來(lái)獲取錯(cuò)誤信息和執(zhí)行狀態(tài)改變
// 五、監(jiān)聽(tīng)當(dāng)前命令是否正在執(zhí)行executing
// 六辣恋、使用場(chǎng)景,監(jiān)聽(tīng)按鈕點(diǎn)擊亮垫,網(wǎng)絡(luò)請(qǐng)求
3.2點(diǎn)擊登錄按鈕VC文件
VC頭屬性
@property (weak, nonatomic) IBOutlet UITextField *userNameTextField;
@property (weak, nonatomic) IBOutlet UITextField *passwordTextField;
@property (weak, nonatomic) IBOutlet UIButton *listButton;
@property (weak, nonatomic) IBOutlet UIButton *loginButton;
@property(nonatomic,strong)FanLoginViewModel *loginViewModel;
VC m文件里面可以簡(jiǎn)化成
{
self.userNameTextField.text=@"18611723209";
self.passwordTextField.text=@"123456fan";
self.loginViewModel=[[FanLoginViewModel alloc]init];
@weakify(self);
//輸入框文字改變添加訂閱信息
// [self.userNameTextField.rac_textSignal subscribeNext:^(NSString * _Nullable x) {
// NSLog(@"=====:%@",x);
// }];
//把文本信號(hào)綁定到ViewModel里面的userName屬性上
RAC(self.loginViewModel,userName)=self.userNameTextField.rac_textSignal;
RAC(self.loginViewModel,password)=self.passwordTextField.rac_textSignal;
//訂閱username改變(可以直接放在loginViewModel里面解決)
[[[[RACObserve(self.loginViewModel, userName) ignore:nil]filter:^BOOL(id _Nullable value) {
//filter過(guò)濾 ignore忽略掉為""的字符串
return [value length]>0;//長(zhǎng)度大于0開(kāi)始執(zhí)行
}] map:^id _Nullable(id _Nullable value) {
//這里可以改變?cè)瓟?shù)據(jù)(直接修改輸入框里面的值,返回)
return value;
}] subscribeNext:^(id _Nullable x) {
//值改變的訂閱 類(lèi)似于rac_textSignal信號(hào)訂閱一樣
}];
//按鈕信號(hào)綁定到ViewModel的兩個(gè)信號(hào)上伟骨,便于在ViewModel里面操作
self.listButton.rac_command=self.loginViewModel.listCommand;
self.loginButton.rac_command=self.loginViewModel.loginCommand;
//當(dāng)用戶(hù)名長(zhǎng)度>0時(shí)饮潦,數(shù)據(jù)信號(hào)綁定到按鈕的enable屬性上 merge合并信號(hào)
// RAC(self.loginButton,enabled) =[[RACObserve(self.userNameTextField, text) merge:self.userNameTextField.rac_textSignal ] map:^id(NSString *value) {
// return @(value.length>0);
// }];
//需要確保loginViewModel初始化,不然就沒(méi)有信號(hào)
//訂閱方式一:rac_liftSelector會(huì)自動(dòng)線(xiàn)執(zhí)行一次 skip跳過(guò)第一次默認(rèn)的執(zhí)行
[self rac_liftSelector:@selector(toggleHUD:) withSignals:[RACObserve(self.loginViewModel, executing) skip:1], nil];
//訂閱方式二:
[self rac_liftSelector:@selector(showMessage:) withSignals:[[RACObserve(self.loginViewModel, error) ignore:nil] map:^id (id value) {
return [value localizedDescription];
}], nil];
[[RACObserve(self.loginViewModel, modelDic) ignore:nil] subscribeNext:^(id x) {
@strongify(self);
[self showMessage:@"登錄成功"];
//跳轉(zhuǎn)到
NSLog(@"登錄結(jié)果:%@",x);
NSDictionary *dic=(NSDictionary *)x;
NSString *session=dic[@"data"][@"PHPSESSID"];
[FanAppManager shareManager].phpsession=session;
}];
//這個(gè)錯(cuò)誤也可以提到ViewModel里面底靠,簡(jiǎn)化vc代碼
[[RACObserve(self.loginViewModel, error) ignore:nil] subscribeNext:^(id x) {
// @strongify(self);
NSLog(@"error:%@",x);
}];
}
-(void)toggleHUD:(NSNumber *)state{
if ([state boolValue]) {
[self showMessage:@"正在執(zhí)行"];
}else{
[self showMessage:@"執(zhí)行完畢"];
}
}
-(void)showMessage:(NSString *)msg{
NSLog(@"msg:%@",msg);
}
3.3 ViewModel實(shí)現(xiàn)
FanLoginViewModel.h
@interface FanLoginViewModel : FanRACViewModel
@property (nonatomic, strong) NSString *userName;
@property (nonatomic, strong) NSString *password;
@property (nonatomic, strong) RACCommand *listCommand;
@property (nonatomic, strong) RACCommand *loginCommand;
/**
* 錯(cuò)誤
*/
@property (nonatomic, strong) NSError *error;
/**
* 是否正在執(zhí)行
*/
@property (nonatomic, strong) NSNumber *executing;
//網(wǎng)絡(luò)請(qǐng)求接口的處理后的字典數(shù)據(jù)
@property (nonatomic, strong) NSMutableDictionary *modelDic;
@end
FanLoginViewModel.m
#import "FanLoginViewModel.h"
#import "FanAPIManager.h"
@interface FanLoginViewModel()
@property (nonatomic, strong) FanAPIManager *apiManager;
@end
@implementation FanLoginViewModel
- (instancetype)init{
if((self = [super init])) {
//初始化網(wǎng)絡(luò)請(qǐng)求類(lèi)
self.apiManager=[[FanAPIManager alloc]init];
}
return self;
}
-(RACCommand *)loginCommand{
if (_loginCommand==nil) {
@weakify(self);
_loginCommand=[[RACCommand alloc]initWithEnabled:[RACSignal combineLatest:@[RACObserve(self, userName), RACObserve(self, password)] reduce:^id (NSString *userName, NSString *password){
//校驗(yàn)輸入規(guī)則害晦,同時(shí)會(huì)綁定按鈕的enable屬性(這里可以對(duì)輸入校驗(yàn))
//這里可以用正則表達(dá)式
return @(YES);
}] signalBlock:^RACSignal * _Nonnull(id _Nullable input) {
//2.網(wǎng)絡(luò)請(qǐng)求得到結(jié)果
ShowHUDIMPMessage(@"加載中");
@strongify(self);
return [self.apiManager loginWithUserName:self.userName isEmail:NO countryCode:@"86" password:self.password];
}] ;
//concat: 連接信號(hào),第一個(gè)信號(hào)必須發(fā)送完成,第二個(gè)信號(hào)才會(huì)被激活
// 1.RACCommand有個(gè)執(zhí)行信號(hào)源executionSignals暑中,這個(gè)是signal of signals(信號(hào)的信號(hào)),意思是信號(hào)發(fā)出的數(shù)據(jù)是信號(hào)壹瘟,不是普通的類(lèi)型。
// 2.訂閱executionSignals就能拿到RACCommand中返回的信號(hào)鳄逾,然后訂閱signalBlock返回的信號(hào)稻轨,就能獲取發(fā)出的值。
//把網(wǎng)絡(luò)請(qǐng)求的信號(hào)的數(shù)據(jù)合并到這個(gè)輸出里面
[[_loginCommand.executionSignals concat] subscribeNext:^(id _Nullable x) {
//3.訂閱結(jié)果
@strongify(self);
self.modelDic = x;
}];
// switchToLatest:用于signal of signals雕凹,獲取signal of signals發(fā)出的最新信號(hào),也就是可以直接拿到RACCommand中的信號(hào)
// [_loginCommand.executionSignals.switchToLatest subscribeNext:^(id _Nullable x) {
//
// }];
[_loginCommand.errors subscribeNext:^(NSError * _Nullable x) {
//4.訂閱錯(cuò)誤信息
@strongify(self);
self.error = x;
//下面這個(gè)是我測(cè)試打印的消息殴俱,因?yàn)槟玫降氖嵌M(jìn)制政冻,后臺(tái)的崩潰數(shù)據(jù),不是正常的error
NSData *errorData=self.error.userInfo[FanRACAFNErrorKey];
NSString *resultStr=[[NSString alloc]initWithData:errorData encoding:NSUTF8StringEncoding];
if (resultStr==nil) {
resultStr=@"data->UTF8 = null";
}
NSLog(@"error:%@",resultStr);
}];
[_loginCommand.executing subscribeNext:^(NSNumber * _Nullable x) {
//訂閱執(zhí)行的狀態(tài)
@strongify(self);
//如果VC文件里面訂閱了這個(gè)值线欲,就能拿到這個(gè)值的狀態(tài)信息明场,做出不同的UI展示
self.executing = x;
if ([self.executing boolValue]) {
HideHUDAll;
}
}];
}
return _loginCommand;
}
@end
3.4 AFHTTPSessionManager+FanRACExtension 擴(kuò)展實(shí)現(xiàn)
我把AFHTTPSessionManager
這個(gè)類(lèi)寫(xiě)了一個(gè)信號(hào)的擴(kuò)展,以前有個(gè)pod庫(kù)李丰,但是很舊了苦锨,仿寫(xiě)了一個(gè)最新的,主要目的就是使用信號(hào)量可以從UI綁定到網(wǎng)絡(luò)請(qǐng)求趴泌,全部弄成RAC框架模式舟舒,當(dāng)然,其他的第三方庫(kù)嗜憔,你也可以仿照寫(xiě)一個(gè)信號(hào)量秃励。
extern NSString *const FanRACAFNErrorKey;
@interface AFHTTPSessionManager (FanRACExtension)
///GET
-(RACSignal*)fan_racGET:(NSString *)URLString parameters:(nullable id)parameters;
///GET-Headers
-(RACSignal*)fan_racGET:(NSString *)URLString parameters:(nullable id)parameters headers:(nullable NSDictionary<NSString *,NSString *> *)headers;
///HEAD
-(RACSignal*)fan_racHEAD:(NSString *)URLString parameters:(nullable id)parameters;
///HEAD-Headers
-(RACSignal*)fan_racHEAD:(NSString *)URLString parameters:(nullable id)parameters headers:(nullable NSDictionary<NSString *,NSString *> *)headers;
///POST
-(RACSignal*)fan_racPOST:(NSString *)URLString parameters:(nullable id)parameters;
///POST-Headers
-(RACSignal*)fan_racPOST:(NSString *)URLString parameters:(nullable id)parameters headers:(nullable NSDictionary<NSString *,NSString *> *)headers;
///PUT
-(RACSignal*)fan_racPUT:(NSString *)URLString parameters:(nullable id)parameters;
///PUT-Headers
-(RACSignal*)fan_racPUT:(NSString *)URLString parameters:(nullable id)parameters headers:(nullable NSDictionary<NSString *,NSString *> *)headers;
///PATH
-(RACSignal*)fan_racPATCH:(NSString *)URLString parameters:(nullable id)parameters;
///PATH-Headers
-(RACSignal*)fan_racPATCH:(NSString *)URLString parameters:(nullable id)parameters headers:(nullable NSDictionary<NSString *,NSString *> *)headers;
///DELETE
-(RACSignal*)fan_racDELETE:(NSString *)URLString parameters:(nullable id)parameters;
///DELETE-Headers
-(RACSignal*)fan_racDELETE:(NSString *)URLString parameters:(nullable id)parameters headers:(nullable NSDictionary<NSString *,NSString *> *)headers;
///GET-POST-PUT等等-通用方法
- (RACSignal *)fan_racWithHTTPMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(nullable id)parameters
headers:(nullable NSDictionary <NSString *, NSString *> *)headers
uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgress
downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgress;
///POST-Headers-Upload File(上傳文件)
-(RACSignal*)fan_racPOST:(NSString *)URLString parameters:(nullable id)parameters headers:(nullable NSDictionary<NSString *,NSString *> *)headers constructingBodyWithBlock:(nullable void (^)(id <AFMultipartFormData> formData))block progress:(void (^)(NSProgress * _Nonnull))uploadProgress;
m文件可以在源碼里面查看
3.5 ReactiveCocoa其他注意點(diǎn)和方法
我們知道RACCommand
主要用于按鈕綁定事件,那么其他的UIKit常用框架都被RAC封裝了一遍,都有我們需要常用的信號(hào)量吉捶,使用起來(lái)可以通過(guò)一個(gè)按鈕夺鲜,和文本框,逐漸帚稠,由淺入深谣旁,深入了解ReactiveCocoa的強(qiáng)大床佳,和他的響應(yīng)式設(shè)計(jì)理念滋早,及配合MVVM框架使用方法
-
FanAPIManager
可以看下這個(gè)類(lèi)封裝,就是一個(gè)基本網(wǎng)絡(luò)庫(kù)的封裝砌们,可以繼承他杆麸,實(shí)現(xiàn)比如分模塊處理,用戶(hù)登錄浪感,其他模塊昔头,可以把網(wǎng)絡(luò)請(qǐng)求數(shù)據(jù)解析的動(dòng)作封裝進(jìn)入,用戶(hù)信號(hào)訂閱的直接是需要的數(shù)據(jù)影兽,或者需要的錯(cuò)誤數(shù)據(jù)(當(dāng)然需要后臺(tái)配合寫(xiě)一條完善的接口揭斧,不然亂七八糟,不容易封裝) -
rac_signalForSelector
:用于替代代理峻堰。 -
rac_valuesAndChangesForKeyPath
:用于監(jiān)聽(tīng)某個(gè)對(duì)象的屬性改變讹开。 -
rac_signalForControlEvents
:用于監(jiān)聽(tīng)某個(gè)事件。 -
rac_addObserverForName
:用于監(jiān)聽(tīng)某個(gè)通知捐名。 -
rac_textSignal
:只要文本框發(fā)出改變就會(huì)發(fā)出這個(gè)信號(hào)旦万。 -
rac_liftSelector:withSignalsFromArray:Signals
:當(dāng)傳入的Signals(信號(hào)數(shù)組),每一個(gè)signal都至少sendNext過(guò)一次镶蹋,就會(huì)去觸發(fā)第一個(gè)selector參數(shù)的方法成艘。
使用注意:幾個(gè)信號(hào)赏半,參數(shù)一的方法就幾個(gè)參數(shù),每個(gè)參數(shù)對(duì)應(yīng)信號(hào)發(fā)出的數(shù)據(jù)淆两。
更新歷史(Version Update)
Release 0.0.1
- 通過(guò)簡(jiǎn)單的用戶(hù)登錄接口實(shí)現(xiàn) 網(wǎng)絡(luò)信號(hào)封裝断箫,VM封裝