簡(jiǎn)介
什么是RAC?ReactiveCocoa(簡(jiǎn)稱RAC),是由Github開源的一個(gè)應(yīng)用于iOS和OS開發(fā)的新框架,Cocoa是蘋果整套框架的簡(jiǎn)稱,因此很多蘋果框架喜歡以Cocoa結(jié)尾如蚜。借用RayWenderlich上面的話:
As an iOS developer, nearly every line of code you write is in reaction to some event; a button tap, a received network message, a property change (via Key Value Observing) or a change in user’s location via CoreLocation are all good examples. However, these events are all encoded in different ways; as actions, delegates, KVO, callbacks and others. ReactiveCocoa defines a standard interface for events, so they can be more easily chained, filtered and composed using a basic set of tools.
翻譯過來就是:
作為一個(gè)iOS開發(fā)者或辖,你寫的每一行代碼幾乎都是在響應(yīng)某個(gè)事件,例如按鈕的點(diǎn)擊穗椅,收到網(wǎng)絡(luò)消息使鹅,屬性的變化(通過KVO)或者用戶位置的變化(通過CoreLocation)
挫鸽。但是這些事件都用不同的方式來處理昧碉,比如action、delegate诗赌、KVO汗茄、callback等
。ReactiveCocoa為事件定義了一個(gè)標(biāo)準(zhǔn)接口境肾,從而可以使用一些基本工具來更容易的連接剔难、過濾和組合。
RAC是由Matt Thompson大神開發(fā)的,很多開發(fā)者對(duì)其的評(píng)價(jià)是開啟一個(gè)新的Objective-C紀(jì)元奥喻。
- 以下是RAC的Github主頁:ReactiveCocoa
- 以及官方給出的用法鏈接
安裝
ReactiveCocoa用pod安裝即可偶宫。
本文的Demo可在文章最后下載,在閱讀本文的時(shí)候,強(qiáng)烈推薦邊看Demo邊看博文。
項(xiàng)目中加入了ReactiveCocoa和DeveloperLx的打印插件LxDBAnything同時(shí)加入了鍵盤相應(yīng)的第三方IQKeyboardManager,以及Masonry,使用方法可以看這篇文章:iOS – Masonry自動(dòng)布局(Autolayout)环鲤。
代碼
第一部分 簡(jiǎn)單使用
文本框事件
原來我們?cè)谑褂胻extFiled的時(shí)候我們需要寫到
[textField addTarget:self action:@selector(textChanged:) forControlEvents:UIControlEventEditingChanged];
然后實(shí)現(xiàn)textChanged:方法,在RAC中,對(duì)于文本框的監(jiān)聽,是非常簡(jiǎn)單的一件事情,看如下代碼:
UITextField * textField = ({
UITextField * textField = [[UITextField alloc]init];
textField.backgroundColor = [UIColor cyanColor];
textField;
});
[self.view addSubview:textField];
@weakify(self); // __weak __typeof__(self) self_weak_ = self;
[textField mas_makeConstraints:^(MASConstraintMaker *make) {
@strongify(self); // __strong __typeof__(self) self = self_weak_;
make.size.mas_equalTo(CGSizeMake(180, 40));
make.center.equalTo(self.view);
}];
[[textField rac_signalForControlEvents:UIControlEventEditingChanged]
subscribeNext:^(id x) {
LxDBAnyVar(x);
}];
[textField.rac_textSignal subscribeNext:^(NSString *x) {
LxDBAnyVar(x);
}];
打印結(jié)果:
??__31-[ViewController textFiledTest]_block_invoke_2 + 215?? x = 12
??__31-[ViewController textFiledTest]_block_invoke241 + 211?? x = 0x7fe810c51a90; frame = (97.5 313.5; 180 40); text = '123'; clipsToBounds = YES; opaque = NO; gestureRecognizers = 0x7fe810f58fb0>; layer = 0x7fe810c51600>>
??__31-[ViewController textFiledTest]_block_invoke_2 + 215?? x = 123
??__31-[ViewController textFiledTest]_block_invoke241 + 211?? x = 0x7fe810c51a90; frame = (97.5 313.5; 180 40); text = '1231'; clipsToBounds = YES; opaque = NO; gestureRecognizers = 0x7fe810f58fb0>; layer = 0x7fe810c51600>>
??__31-[ViewController textFiledTest]_block_invoke_2 + 215?? x = 1231
??__31-[ViewController textFiledTest]_block_invoke241 + 211?? x = 0x7fe810c51a90; frame = (97.5 313.5; 180 40); text = '12312'; clipsToBounds = YES; opaque = NO; gestureRecognizers = 0x7fe810f58fb0>; layer = 0x7fe810c51600>>
??__31-[ViewController textFiledTest]_block_invoke_2 + 215?? x = 12312
??__31-[ViewController textFiledTest]_block_invoke241 + 211?? x = 0x7fe810c51a90; frame = (97.5 313.5; 180 40); text = '123123'; clipsToBounds = YES; opaque = NO; gestureRecognizers = 0x7fe810f58fb0>; layer = 0x7fe810c51600>>
??__31-[ViewController textFiledTest]_block_invoke_2 + 215?? x = 123123
我們很容易的監(jiān)聽到textFiled中發(fā)生的變化,其中x的類型默認(rèn)為id類型,我們已知它的類型的時(shí)候我們可以將其改變,就像上面代碼,將id改成NSString類型纯趋。
手勢(shì)
self.view.userInteractionEnabled = YES;
UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc]init];
[[tap rac_gestureSignal] subscribeNext:^(UITapGestureRecognizer * tap) {
LxDBAnyVar(tap);
}];
[self.view addGestureRecognizer:tap];
為了方便,我們直接添加到self.view上,點(diǎn)擊屏幕,得到打印結(jié)果:
??__29-[ViewController gestureTest]_block_invoke + 184?? tap = 0x7fa2e3e1f9f0; state = Ended; view = 0x7fa2e3e20b70>; target= action=sendNext:, target=0x7fa2e3c064f0>)>>
通知
[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIApplicationDidEnterBackgroundNotification object:nil] subscribeNext:^(NSNotification * notification) {
LxDBAnyVar(notification);
}];
我們建立了一個(gè)通知,叫做進(jìn)入后臺(tái),當(dāng)程序進(jìn)入后臺(tái)的時(shí)候通知相應(yīng),當(dāng)我們用RAC寫通知的時(shí)候,我們有一個(gè)好處,就是不用removeObserve通知,因?yàn)镽AC通知的監(jiān)聽者是RAC自己,它會(huì)幫你管理釋放方法±淅耄可以看方法實(shí)現(xiàn)如下:
- (RACSignal *)rac_addObserverForName:(NSString *)notificationName object:(id)object {
@unsafeify(object);
return [[RACSignal createSignal:^(idRACSubscriber> subscriber) {
@strongify(object);
id observer = [self addObserverForName:notificationName object:object queue:nil usingBlock:^(NSNotification *note) {
[subscriber sendNext:note];
}];
return [RACDisposable disposableWithBlock:^{
[self removeObserver:observer];
}];
}] setNameWithFormat:@"-rac_addObserverForName: %@ object: ", notificationName, [object class], object];
}
定時(shí)器
//1. 延遲某個(gè)時(shí)間后再做某件事
[[RACScheduler mainThreadScheduler]afterDelay:2 schedule:^{
LxPrintAnything(rac);
}];
//2. 每間隔多長(zhǎng)時(shí)間做一件事
[[RACSignal interval:1 onScheduler:[RACScheduler mainThreadScheduler]]subscribeNext:^(NSDate * date) {
LxDBAnyVar(date);
}];
這是定時(shí)器最常用的兩種寫法,第一種方法,延遲時(shí)間去做某件事情,更改afterDelay的屬性吵冒。
第二種方法,每間隔多長(zhǎng)時(shí)間做一件事情,更改interval屬性。
代理
UIAlertView * alertView = [[UIAlertView alloc]initWithTitle:@"RAC" message:@"ReactiveCocoa" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Ensure", nil];
[[self rac_signalForSelector:@selector(alertView:clickedButtonAtIndex:) fromProtocol:@protocol(UIAlertViewDelegate)] subscribeNext:^(RACTuple * tuple) {
LxDBAnyVar(tuple);
LxDBAnyVar(tuple.first);
LxDBAnyVar(tuple.second);
LxDBAnyVar(tuple.third);
}];
[alertView show];
// 更簡(jiǎn)單的方式:
[[alertView rac_buttonClickedSignal]subscribeNext:^(id x) {
LxDBAnyVar(x);
}];
用RAC去寫代理的時(shí)候,會(huì)有局限,只能取代沒有返回值的代理方法,什么是沒有返回值的代理呢?比如說tableView的代理方法:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath