ReactiveCocoa框架的使用教程在網(wǎng)上有很多詳細(xì)的博客可參考,通過學(xué)習(xí)覆履,我自己也整理了一下究恤,一來便于自己復(fù)習(xí)俭令,二來分享給大家。先粘貼些優(yōu)質(zhì)博文的鏈接部宿,然后下面以實(shí)例的形式一步步講解抄腔。
優(yōu)質(zhì)技術(shù)博客鏈接
地址1:ReactiveCocoa入門教程——第一部分
地址2:ReactiveCocoa入門教程——第二部分
地址3:1個(gè)小時(shí)學(xué)會(huì)ReactiveCocoa基本使用
下面開始介紹ReactiveCocoa的使用
一、在項(xiàng)目中集成ReactiveCocoa框架
既然是第三方框架理张,那用CocoaPods集成是最方便的赫蛇。
首先,創(chuàng)建一個(gè)工程
然后雾叭,在工程中創(chuàng)建Podfile文件悟耘,文件中的內(nèi)容如下:
platform :ios,'9.0'
use_frameworks!
target 'RWReactivePlayground' do
pod 'ReactiveCocoa', '~> 2.5'
end
注意1:
集成ReactiveCocoa框架和其他的不同之處是多了一個(gè)“use_frameworks!”,我在使用過程中發(fā)現(xiàn)织狐,2.5版本以上的更高的版本要加上“use_frameworks!”暂幼,否則會(huì)報(bào)錯(cuò),導(dǎo)致集成不了。而2.5版本之前的(包括2.5版本)移迫,就不需要加“use_frameworks!”旺嬉,
注意2:
ReactiveCocoa現(xiàn)在的最高版本已經(jīng)到5.0了,問題是厨埋,如果用swift編程邪媳,那么集成最新版本的ReactiveCocoa框架沒有問題,但是如果使用OC編程的話荡陷,那最高只能集成2.5版本的RAC(RAC是ReactiveCocoa的簡稱)雨效,否則集成好了以后工程會(huì)報(bào)錯(cuò)。
簡單的說就是废赞,如果你用swift編程肮塞,用Cocoapods集成時(shí)犯建,Podfile文件這么寫
platform :ios,'9.0'
use_frameworks!
target 'RWReactivePlayground' do
pod 'ReactiveCocoa', '~> 5.0'
end
如果你用的是oc編程夫啊,用Cocoapods集成時(shí),Podfile文件這么寫
platform :ios,'9.0'
target 'RWReactivePlayground' do
pod 'ReactiveCocoa', '~> 2.5'
end
最后戏溺,上面的工作都做好了,就可以集成RAC了屠尊,很快.
二旷祸、RAC的簡單使用----RACSignal
在要使用的RAC的控制器中導(dǎo)入RAC框架的頭文件
#import <ReactiveCocoa/ReactiveCocoa.h>
現(xiàn)在來熟悉下RACSignal的使用,從名字就可以看出讼昆,它是信號(hào)托享。在viewDidload中加入下面的代碼
//創(chuàng)建信號(hào)
RACSignal * single = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"想");
[subscriber sendNext:@"發(fā)送了信號(hào)"];//發(fā)送信號(hào)
NSLog(@"你");
[subscriber sendCompleted];//發(fā)送完成,訂閱自動(dòng)移除
//RACDisposable 可用于手動(dòng)移除訂閱
return [RACDisposable disposableWithBlock:^{
NSLog(@"豆腐");
}];
}];
//訂閱信號(hào)
NSLog(@"我");
[single subscribeNext:^(id x) {
NSLog(@"吃");
// NSLog(@"信號(hào)的值:%@",x);
}];
運(yùn)行浸赫,得到結(jié)果如下
這樣就可以清楚的看明白闰围,信號(hào)的運(yùn)行流程,但是感覺好亂既峡,下面分析一下:
1.createSignal方法 是創(chuàng)建信號(hào)羡榴,創(chuàng)建好的信號(hào),沒有被訂閱前运敢,只是冷信號(hào)校仑,此時(shí)是不會(huì)走createSignal后面的block的。
程序往下传惠,就走到“NSLog(@"我")”迄沫,
2.然后走到subscribeNext,這一步就是訂閱信號(hào)卦方,訂閱號(hào)信號(hào)后羊瘩,信號(hào)single就變成了熱信號(hào),
3.既然變成熱信號(hào),就開始走createSignal后面的block中的去盼砍,所以就打印出了“NSLog(@"想")”尘吗。
4.下面是sendNext,即發(fā)送信號(hào)衬廷,發(fā)送了信號(hào)摇予,訂閱者就會(huì)收到信號(hào)汽绢,發(fā)送的內(nèi)容可以從訂閱信號(hào)subscribeNext后面的block中獲取到吗跋,程序就走到subscribeNext后面的block中,所以就打印了“NSLog(@"吃")”宁昭,
5.當(dāng)訂閱信號(hào)的subscribeNext后面的block走完以后跌宛,程序又回到,createSignal后面的block中积仗,繼續(xù)未完成的代碼疆拘,所以就打印“NSLog(@"你")”,繼續(xù)往下就是[subscriber sendCompleted]寂曹,這句代碼的意思是哎迄,發(fā)送完成了回右,訂閱自動(dòng)移除,沒有了訂閱者了漱挚,信號(hào)又變成了冷信號(hào)翔烁。
6.接下來就是return,返回一個(gè)RACDisposable對(duì)象,這個(gè)的作用就是旨涝,可以用來手動(dòng)移除訂閱蹬屹。RACDisposable對(duì)象,創(chuàng)建完成白华,就走進(jìn)創(chuàng)建方法的block中慨默,也就是打印NSLog(@"豆腐")
綜上,打印出來的結(jié)果就是“我想吃你豆腐”弧腥,它就是這樣出來的
這里再介紹下RACDisposable的使用厦取,將代碼改一下
//創(chuàng)建信號(hào)
RACSignal * single = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"想");
[subscriber sendNext:@"發(fā)送了一個(gè)信號(hào)"];//發(fā)送信號(hào)
NSLog(@"你");
//RACDisposable 手動(dòng)移除訂閱者
return [RACDisposable disposableWithBlock:^{
NSLog(@"豆腐");
}];
}];
//訂閱信號(hào)
NSLog(@"我");
RACDisposable * disposable = [single subscribeNext:^(id x) {
NSLog(@"吃");
NSLog(@"信號(hào)的值:%@",x);
}];
//手動(dòng)移除訂閱
[disposable dispose];
打印結(jié)果如下
在稍微分析一下,兩份代碼不同之處是管搪,刪去了自動(dòng)移除訂閱[subscriber sendCompleted]蒜胖,添加了手動(dòng)刪除訂閱[disposable dispose],手動(dòng)刪除訂閱抛蚤,可以在你想要的地方台谢,合適的時(shí)候進(jìn)行操作。不過手動(dòng)刪除用的少岁经。那既然用得少朋沮,我們還是用自動(dòng)刪除吧,優(yōu)化下缀壤,見代碼
//創(chuàng)建信號(hào)
RACSignal * single = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"想");
[subscriber sendNext:@"發(fā)送了信號(hào)"];//發(fā)送信號(hào)
NSLog(@"你");
[subscriber sendCompleted];//發(fā)送完成樊拓,訂閱自動(dòng)移除
//RACDisposable 手動(dòng)移除訂閱者
return nil;
}];
//訂閱信號(hào)
NSLog(@"我");
[single subscribeNext:^(id x) {
NSLog(@"吃");
NSLog(@"信號(hào)的值:%@",x);
}];
打印結(jié)果如下
好了,沒豆腐吃了塘慕!其實(shí)也不需要筋夏。返回nil就可以了
上面羅里吧嗦的說了那么多,就是為了理清里面的邏輯图呢,沒有結(jié)合實(shí)際使用条篷,其實(shí)聽起來還是很迷糊,下面就結(jié)合實(shí)際蛤织,來使用RAC
第二赴叹、RAC的常用方法
上面是使用RACSignal創(chuàng)建信號(hào),其實(shí)文本框中文字改變也是信號(hào)指蚜,按鈕點(diǎn)擊也是信號(hào)乞巧,RAC為UITxtField和UIButton創(chuàng)建categary,并做好了封裝,直接就可以調(diào)用它們的信號(hào)摊鸡,這里就圍繞著這兩個(gè)類绽媒,進(jìn)行ARC的使用講解
在工程中新建一個(gè)控制器蚕冬,添加幾個(gè)控件,textField,textView,button,label,如下圖
訂閱textField信號(hào)
[self.textfield.rac_textSignal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
因?yàn)閠extField的信號(hào)肯定是NSString,類型的是辕,所以可以寫成下面的樣子播瞳,也更方便使用些
[self.textfield.rac_textSignal subscribeNext:^(NSString* x) {
NSLog(@"%@",x);
}];
這樣,當(dāng)你在文本框輸入時(shí)免糕,控制臺(tái)就會(huì)打印出輸入的內(nèi)容赢乓,如下
可以看到,每次輸入都會(huì)獲取到信號(hào)石窑。
filter---信號(hào)過濾器
如果我只需要將字符串長度超過3的牌芋,才打印,那可以使用過濾器filter松逊,使用方法如下
[[self.textfield.rac_textSignal filter:^BOOL(NSString* value) {
return value.length>3?YES:NO;
}]subscribeNext:^(NSString* x) {
NSLog(@"過濾后的到的信號(hào):%@",x);
}];
在文本框中輸入字符躺屁,打印結(jié)果如下
可以看到,只有當(dāng)字符串長度大于3的信號(hào)经宏,才會(huì)被訂閱到
map--轉(zhuǎn)換器
map就是將一種信號(hào)轉(zhuǎn)換成你想要的另一種信號(hào)犀暑,這里把字符串信號(hào),轉(zhuǎn)換成文字信號(hào)
如果想當(dāng)文本框中輸入的文字長度大于4的時(shí)候烁兰,改變文本框的背景色耐亏,一種方法是把過濾器的條件設(shè)置為4,然后在subscribeNext的block中直接給textField.backgroundColor賦值沪斟。不過RAC有轉(zhuǎn)換信號(hào)的方法---map,如下
[[[self.textfield.rac_textSignal filter:^BOOL(NSString* value) {
return value.length>3?YES:NO;
}]map:^id(NSString* value) {
return value.length > 4?[UIColor redColor]:[UIColor whiteColor];
}]subscribeNext:^(UIColor* value) {
self.textfield.backgroundColor = value;
}];
上面的代碼的意思是广辰,當(dāng)輸入的字符串長度超過3,就將字符串信號(hào)轉(zhuǎn)換成顏色信號(hào)主之,然后訂閱該顏色信號(hào)择吊,并將顏色賦值給textField的背景色。效果如下
這樣的話槽奕,當(dāng)字符串大于3几睛,文本框的背景色變成了紅色
另外,RAC提供了一個(gè)宏"RAC(對(duì)象,屬性)"來簡化代碼并增強(qiáng)可讀性粤攒,如下
RAC(self.textfield ,backgroundColor) = [self.textfield.rac_textSignal map:^id(NSString* value) {
return value.length > 4?[UIColor redColor]:[UIColor whiteColor];
}];
RAC宏有兩個(gè)參數(shù)所森,一個(gè)是需要設(shè)置的對(duì)象,一個(gè)是設(shè)置的屬性琼讽。這句代碼的意思是必峰,當(dāng)文本框輸入的字符串長度大于4時(shí),改變文本框的背景色钻蹬。這樣的話,看起來更清晰凭需,而達(dá)到的效果是一樣的问欠。
總結(jié)一下肝匆,到現(xiàn)在為止,學(xué)了過濾器:filter,轉(zhuǎn)換器:map,對(duì)象設(shè)置屬性的宏:RAC(要設(shè)置的對(duì)象顺献,要設(shè)置的屬性)旗国。可以想象注整,用這幾個(gè)方法可以很方便的實(shí)現(xiàn)一些功能能曾,比喻說替代通知,監(jiān)聽事件等肿轨。
textField的使用是這樣寿冕,那textView的使用也是這樣的,因?yàn)樗麄兺耆愃?/p>
RAC(self.textView ,backgroundColor) = [self.textView.rac_textSignal map:^id(NSString* value) {
return value.length > 4?[UIColor redColor]:[UIColor whiteColor];
}];
combineLatest:reduce:
想象一下,如果當(dāng)textField和textView同時(shí)滿足某個(gè)條件時(shí)椒袍,才能進(jìn)行某項(xiàng)操作的話驼唱,應(yīng)該如何寫呢?RAC為我們準(zhǔn)備了一個(gè)方法--combineLatest:reduce:信號(hào)合并
先看代碼
RACSignal * mergeTwoSignal = [RACSignal combineLatest:@[self.textfield.rac_textSignal,self.textView.rac_textSignal] reduce:^id(NSString * value1,NSString * value2){
return [NSNumber numberWithBool:([value1 isEqualToString:@"11111"]&&[value2 isEqualToString:@"22222"])];
}];
RAC(self.addButton,enabled) = [mergeTwoSignal map:^id(NSNumber* value) {
return value;
}];
上面的代碼的意思是驹暑,當(dāng)textField中的文字為"11111",同時(shí)textView中的文字為"22222"的時(shí)候玫恳,返回一個(gè)信號(hào),信號(hào)的類型是NSNumber,然后通過轉(zhuǎn)換器map优俘,將值返回京办,返回的值用于確定按鈕是否可用。
可能會(huì)疑問帆焕,map中返回的NSNumber類型的臂港,而button的enabled屬性是BOOL類型,怎么可以這樣直接賦值视搏,但是RAC它就是可以审孽,就是做的這么好。
到這一步浑娜,就可以訂閱button的點(diǎn)擊信號(hào)了佑力,看代碼就懂了
[[self.addButton rac_signalForControlEvents:(UIControlEventTouchUpInside)]
subscribeNext:^(NSNumber * value) {
//標(biāo)簽賦值
self.displayLabel.text = @"1314";
}];
運(yùn)行驗(yàn)證一下,結(jié)果如下
確實(shí)能達(dá)到要求筋遭。真好打颤,再也不用給button 添加點(diǎn)擊事件了。
doNext
現(xiàn)在講一下附加操作doNext漓滔,它的作用是编饺,在不改變信號(hào)的基礎(chǔ)上,進(jìn)行一些附加的操作响驴,比喻說透且,我在訂閱到給label賦值前,改變label的背景色,當(dāng)然也可以是做別的操作秽誊。反正是附加的不會(huì)影響信號(hào)流的鲸沮。使用見代碼
[[[self.addButton rac_signalForControlEvents:(UIControlEventTouchUpInside)]
doNext:^(id x) {
//改變label的背景色
self.displayLabel.backgroundColor = [UIColor redColor];
}]
subscribeNext:^(NSNumber * value) {
self.displayLabel.text = @"1314";
}];
這樣就實(shí)現(xiàn)了,訂閱信號(hào)前锅论,改變label的背景色
@weakify和@strongify
RAC的所有方法中讼溺,大部分是block,所以無法避免在使用過程中導(dǎo)致循環(huán)引用最易,
以前的解決辦法是這樣的
__weak SecondViewController *bself = self;
[[[self.addButton rac_signalForControlEvents:(UIControlEventTouchUpInside)]
doNext:^(id x) {
//先清掉label中的文字
bself.displayLabel.textColor = [UIColor redColor];
}]
subscribeNext:^(NSNumber * value) {
bself.displayLabel.text = @"1314";
}];
如果每個(gè)block都寫的話怒坯,會(huì)很費(fèi)勁,因?yàn)閎lock太多了藻懒,還好RAC提供了兩個(gè)宏剔猿,@weakify和@strongify,
@weakify(self);
[[[self.addButton rac_signalForControlEvents:(UIControlEventTouchUpInside)]
doNext:^(id x) {
@strongify(self);
self.displayLabel.textColor = [UIColor redColor];
}]
subscribeNext:^(NSNumber * value) {
@strongify(self);
self.displayLabel.text = @"1314";
}];
@weakify宏讓你創(chuàng)建一個(gè)弱引用的影子對(duì)象(如果你需要多個(gè)弱引用束析,你可以傳入多個(gè)變量)艳馒,@strongify讓你創(chuàng)建一個(gè)對(duì)之前傳入@weakify對(duì)象的強(qiáng)引用。這樣就解決了循環(huán)引用的問題
第三员寇、RAC在網(wǎng)絡(luò)請(qǐng)求和圖片加載中的使用
先創(chuàng)建一個(gè)控制器弄慰,添加若干控件,textView,用來展示請(qǐng)求到的數(shù)據(jù)蝶锋,imageView陆爽,用來展示圖片,
使用系統(tǒng)的方法請(qǐng)求數(shù)據(jù)
在viewDidload中添加下面的代碼
NSURL * url = [NSURL URLWithString:urlS];
NSURLSession * session = [NSURLSession sharedSession];
NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:url];
NSURLSessionTask * task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSString * dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@",dataString);
NSDictionary * dic = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSLog(@"%@",dic);
[self performSelector:@selector(actionWithString:) onThread:[NSThread mainThread] withObject:dataString waitUntilDone:YES];
}];
[task resume];
//回到主線程給textView賦值
-(void)actionWithString:(id )value{
self.textView.text = (NSString*)value;
}
結(jié)果如下
使用RAC請(qǐng)求網(wǎng)絡(luò)數(shù)據(jù)
把系統(tǒng)請(qǐng)求網(wǎng)絡(luò)數(shù)據(jù)的方法,封裝成信號(hào)流
//rac網(wǎng)絡(luò)請(qǐng)求
-(RACSignal *)racNetworkRequest{
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSURL * url = [NSURL URLWithString:urlS];
NSURLSession * session = [NSURLSession sharedSession];
NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:url];
NSURLSessionTask * task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSString * dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
// NSLog(@"%@",dataString);
// NSDictionary * dic = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
// NSLog(@"%@",dic);
if (error ==nil) {//返回成功
[subscriber sendNext:dataString];//發(fā)送信號(hào)
[subscriber sendCompleted];//結(jié)束發(fā)送
} else {
[subscriber sendError:error];//發(fā)送錯(cuò)誤
}
}];
[task resume];
return nil;
}];
}
現(xiàn)在就來調(diào)用一下看看扳缕,在viewDidLoad中添加下面的代碼,
self.requestDataButton是一個(gè)按鈕慌闭,使用方法是點(diǎn)擊按鈕的時(shí)候加載數(shù)據(jù)
[[[self.requestDataButton rac_signalForControlEvents:(UIControlEventTouchUpInside)]
map:^id(id value) {
return [self racNetworkRequest];
}]
subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
訂閱信號(hào)后,得到的數(shù)據(jù)如下
發(fā)現(xiàn)躯舔,得到的不是想要的數(shù)據(jù)驴剔,而是一個(gè)信號(hào)對(duì)象,其實(shí)從racNetworkRequest這個(gè)方法中就可以看出粥庄,返回就是一個(gè)RACSignal對(duì)象丧失,如果能獲取到RACSignal對(duì)象里面的信號(hào)流就對(duì)了,怎么辦呢惜互,RAC提供了這樣的方法 flattenMap
flattenMap---獲取信號(hào)中的信號(hào)
把上面的代碼寫成這樣布讹,就可以獲取到數(shù)據(jù)了
[[[self.requestDataButton rac_signalForControlEvents:(UIControlEventTouchUpInside)]
flattenMap:^id(id value) {
return [self racNetworkRequest];
}]
subscribeNext:^(id x) {
NSLog(@"%@",x);
} error:^(NSError *error) {
NSLog(@"%@",error);
}];
這樣就會(huì)發(fā)現(xiàn)訂閱到的信號(hào),是你想要的數(shù)據(jù)了训堆。
then---等待上一個(gè)信號(hào)的完成描验,然后訂閱自己的信號(hào)
[[[self racNetworkRequest]
then:^RACSignal *{
return self.textField.rac_textSignal;
}]
subscribeNext:^(id x) {
NSLog(@"%@",x);
}error:^(NSError *error) {
NSLog(@"error");
}];
then方法會(huì)等待前面的信號(hào)中completed事件的發(fā)送完成,然后再訂閱由then block返回的信號(hào)坑鱼。這樣就高效地把控制權(quán)從一個(gè)signal傳遞給下一個(gè)膘流。如此就實(shí)現(xiàn)了:當(dāng)請(qǐng)求數(shù)據(jù)完成,就可以監(jiān)控到textField中的文字輸入了
回到主線程---deliverOn
因?yàn)樾盘?hào)的流轉(zhuǎn)及操作都是在block中完成的,也就是說大部分操作都是在子線程中執(zhí)行的操作睡扬,但是有個(gè)時(shí)候需要回到主線程完成一些事情盟蚣,比如黍析,請(qǐng)求到數(shù)據(jù)后卖怜,要刷新UI,這就必須回到主線程阐枣,RAC提供了這樣的方法deliverOn马靠。用法見下面的代碼
@weakify(self)
[[[[[self racNetworkRequest]
then:^RACSignal *{
@strongify(self);
return self.textField.rac_textSignal;
}]
filter:^BOOL(NSString* value) {
return value.length > 3?YES:NO;
}]
deliverOn:[RACScheduler mainThreadScheduler]]//回到主線程
subscribeNext:^(NSString * value) {
@strongify(self);
self.textView.text =value;
NSLog(@"%@",value);
NSLog(@"當(dāng)前線程%@",[NSThread currentThread]);
} error:^(NSError *error) {
NSLog(@"%@",error);
}];
這樣的話,實(shí)現(xiàn)的效果就是蔼两,在textField中輸入文字而且當(dāng)文字大于3的時(shí)候甩鳄,會(huì)在textView中顯示出來,而且可以看到訂閱信號(hào)的block中打印出來的線程是主線程额划,如下:
悲催的是妙啃,如果沒有加deliverOn:好像也是在主線程。我也不知道什么原因俊戳,不知道有沒有用揖赴,姑且就認(rèn)為deliverOn有用,可能在開啟很多線程的時(shí)候會(huì)有用吧
不過我可以在subscribeNext的block中加入回到主線程的方法,也能達(dá)到目的抑胎,如下
subscribeNext:^(NSString * value) {
@strongify(self);
self.textView.text =value;
NSLog(@"%@",value);
[self performSelectorOnMainThread:@selector(doSomething) withObject:nil waitUntilDone:YES];
NSLog(@"當(dāng)前線程%@",[NSThread currentThread]);
} error:^(NSError *error) {
NSLog(@"%@",error);
}];
信號(hào)節(jié)流---throttle
用文本框textField作比喻燥滑,當(dāng)我在里面輸入字符時(shí),subscribeNext的block會(huì)不停的走阿逃,每輸入一個(gè)字符铭拧,就會(huì)走一遍。如果我想在輸入過程中不需要每改變一個(gè)字符就走一遍恃锉,而是等輸入完成或停止的時(shí)候再走block里面的代碼搀菩,那就可以用throttle,先看效果
[[[self.textField.rac_textSignal
filter:^BOOL(NSString* value) {
return value.length > 3?YES:NO;
}]
throttle:1]
subscribeNext:^(NSString * value) {
@strongify(self);
self.textView.text =value;
} error:^(NSError *error) {
NSLog(@"%@",error);
}];
這樣得到的效果是破托,當(dāng)輸入字符串長度大于3肪跋,而且該字符串的值在1s內(nèi)沒有改變,就把textField中的值炼团,賦值給textView澎嚣。所以簡單的說throttle的作用:如果前面信號(hào)在設(shè)定的時(shí)間內(nèi)沒有變化時(shí),throttle就會(huì)把信號(hào)傳到下面的事件中去瘟芝。
使用系統(tǒng)的方法加載圖片
系統(tǒng)的方法易桃,我就不說了 看代碼
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
NSURL * url = [NSURL URLWithString:imageUrlString];
UIImage * image = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
if (image!=nil) {
dispatch_async(dispatch_get_main_queue(), ^{
self.imageView.image = image;
});
}
});
這樣就可以完成圖片的加載,看下面的效果
RAC加載圖片
創(chuàng)建一個(gè)加載圖片的方法锌俱,方法返回的是RACSignle信號(hào)對(duì)象晤郑,
-(RACSignal*)racRequestImage{
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSURL * url = [NSURL URLWithString:imageUrlString];
UIImage * image = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
self.imageView.image = image;
[subscriber sendNext:image];
[subscriber sendCompleted];
return nil;
}];
}
下面就來調(diào)用這個(gè)方法。實(shí)現(xiàn)的效果是,點(diǎn)擊按鈕(self.requestImageDataButton)造寝,即開始加載圖片磕洪,在viewDidLoad中添加下面的代碼
@weakify(self);
[[[self.requestImageDataButton rac_signalForControlEvents:(UIControlEventTouchUpInside)]
flattenMap:^RACStream *(id value) {
return [self racRequestImage];
}]
deliverOn:[RACScheduler mainThreadScheduler]]
subscribeNext:^(UIImage * image) {
@strongify(self);
self.imageView.image = image;
}];
運(yùn)行一下,發(fā)現(xiàn)诫龙,圖片加載正常析显。從代碼量來看,GCD可能方便一點(diǎn)签赃,但是谷异,如果是多個(gè)事件湊到一起影響圖片加載的時(shí)候,RAC或許是不錯(cuò)的選擇锦聊。
到這一步歹嘹,就把ReactiveCocoa的初步使用講完了。
總結(jié)一下總共學(xué)習(xí)哪些方法