NSData + RACSupport.h @interface NSData (RACSupport) // Read the data at the URL using -[NSData initWithContentsOfURL:options:error:]. // Sends the data or the error. // 返回一个URL异步请求的信号量 // scheduler 不能为空 + (RACSignal *)rac_readContentsOfURL:(NSURL *)URL options:(NSDataReadingOptions)options scheduler:(RACScheduler *)scheduler; @end
NSData
尝试这个例子之前,请在Demo工程的info.plist文件中加入App Transport Security Settings
键值,并加入Allow Arbitrary Loads
:YES
键值对,用来开启iOS下的非安全连接。
可以这样用
NSURL* url = [NSURL URLWithString:@"http://www.jianshu.com"]; RACSignal* getDataSignal = [NSData rac_readContentsOfURL:url options:NSDataReadingUncached scheduler:[RACScheduler mainThreadScheduler]]; [getDataSignal subscribeNext:^(id x) { NSLog(@"%@",x); //这里的x就是NSData数据 }];
map函数
如果我们使用NSData
的rac_readContentsOfURL:url
方法下载的是一张图片,我们肯定希望这个Signal最后输出的是UIImage
对象,这里就要用到非常常用的map
函数。
map
函数就像signal
管道上的中间处理器,从这里走过的signal
都会经过一段处理后,变成新的signal
继续传输。而这个处理过程则在map
函数中由开发者决定。
将输出NSData
的signal
转换为输出UIImage
NSURL* url = [NSURL URLWithString:@"http://img1.gtimg.com/gamezone/pics/24159/24159840.jpg"]; RACSignal* getDataSignal = [NSData rac_readContentsOfURL:url options:NSDataReadingUncached scheduler:[RACScheduler mainThreadScheduler]]; //map函数进行转换 RACSignal* getImageSignal = [getDataSignal map:^id(id value) { if (value) { return [UIImage imageWithData:value]; } return nil; }]; [getImageSignal subscribeNext:^(id x) { NSLog(@"%@",x); }];
merge方法
接着我们提出一个新需求,同时请求三张不同的图片,并将它们发送的信号合并成一条信号量。这里就需要用到信号量的merge
方法,如下
NSURL* url = [NSURL URLWithString:@"http://img1.gtimg.com/gamezone/pics/24159/24159840.jpg"]; NSURL* url2 = [NSURL URLWithString:@"http://i3.hoopchina.com.cn/blogfile/201306/29/137247593017986.jpg"]; NSURL* url3 = [NSURL URLWithString:@"http://img.youxile.com/pic/1301/25170237170.jpg"]; RACSignal* getImageSignal1 = [[NSData rac_readContentsOfURL:url options:NSDataReadingUncached scheduler:[RACScheduler mainThreadScheduler]] map:^id(id value) { if (value) { return [UIImage imageWithData:value]; } return nil; }]; RACSignal* getImageSignal2 = [[NSData rac_readContentsOfURL:url2 options:NSDataReadingUncached scheduler:[RACScheduler mainThreadScheduler]] map:^id(id value) { if (value) { return [UIImage imageWithData:value]; } return nil; }]; RACSignal* getImageSignal3 = [[NSData rac_readContentsOfURL:url3 options:NSDataReadingUncached scheduler:[RACScheduler mainThreadScheduler]] map:^id(id value) { if (value) { return [UIImage imageWithData:value]; } return nil; }]; //合并操作 RACSignal* mergeSignal = [RACSignal merge:@[getImageSignal1,getImageSignal2,getImageSignal3]]; [mergeSignal subscribeNext:^(id x) { NSLog(@"%@",x); }];``` 输出如下: 2015-12-30 10:19:08.776 Fahu[1354:39991] <UIImage: 0x7f9ce2ac3730>, {450, 600} 2015-12-30 10:19:08.891 Fahu[1354:39991] <UIImage: 0x7f9ce2b02600>, {500, 687} 2015-12-30 10:19:09.098 Fahu[1354:39991] <UIImage: 0x7f9ce29a4500>, {500, 346}
###filter函数
网络也会有连不上的时候,三张图片中如果有哪一张请求失败,我们并不想让`signal`发送`nil`值过来,可以使用filter函数对`signal`进行筛选。稍微改造一下上面的`mergeSignal`:
RACSignal* mergeSignal = [[RACSignal merge:@[getImageSignal1,getImageSignal2,getImageSignal3]] filter:^BOOL(id value) { return @(!!value); }];`
注意这里的filter函数返回的是NSNumber型的BOOL值,YES是通过,NO时拒绝通过。
NSURLConnection
有了RAC
,一些简单的网络请求都可以不用AF框架了。
NSURLConnection+RACSupport.h
+ (RACSignal *)rac_sendAsynchronousRequest:(NSURLRequest *)request;``` 举个例子,还是请求图片 NSURL* url = [NSURL URLWithString:@"http://img1.gtimg.com/gamezone/pics/24159/24159840.jpg"]; NSURLRequest* request = [NSURLRequest requestWithURL:url]; RACSignal* connectionSignal = [NSURLConnection rac_sendAsynchronousRequest:request]; [connectionSignal subscribeNext:^(id x) { NSLog(@"%@",x); }];` 输出 <RACTuple: 0x7f826c071c00> ...省略``` 注意,这个`signal`发送的信号量是一个`RACTuple`对象。 ###RACTuple `RACTuple`(元组)类,是`RAC`中专门用来返回多个返回值的类,这个设计很像swift中的元组。 上面例子中的`RACTuple`有两个返回值,`x[0]`是http response的头部信息,`x[1]`是请求返回的数据,是一个`NSData`对象。元组类对象的读取方法和数组相同。