使用AFNetworking, SDWebimage和OHHTTPStubs

ios

写了个示例,放在GitHub上。

这是运行的动画:

以下内容主要介绍:

  • 基于AFNetworking的HTTP操作,GET获取网页和JSON数据,上传文件,下载文件,以及加载图片
  • 基于SDWebimage的加载图片
  • 基于OHHTTPStubs的伪造网络响应用于测试(stub),而且可以模拟出网络的延时

使用基于NSURLSession的AFNetworking API

AFNetworking有2套用于网络操作的API:

  • 基于NSURLConnection
  • 基于NSURLSession

后者是新的API,用于iOS 7 / Mac OS X 10.9及以上版本。

这篇文章写的很好:从 NSURLConnection 到 NSURLSession,说明后者做了哪些改善和加强。

现在越来越多的iOS项目最低要求iOS 7,让我们可以开始尝试使用这种新的方式。

GET请求,获取普通网页文本

AFHTTPSessionManager是使用NSURLSession的API。

      
      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
      
      
NSURL *baseURL = [ NSURL URLWithString: @"http://localhost/"];
//设置和加入头信息
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
[config setHTTPAdditionalHeaders:@{ @"User-Agent" : @"My Browser"}];
AFHTTPSessionManager *manager=[[AFHTTPSessionManager alloc] initWithBaseURL:baseURL sessionConfiguration:config];
manager .responseSerializer = [AFHTTPResponseSerializer serializer];
manager .responseSerializer .acceptableContentTypes = [ NSSet setWithObject: @"text/html"];
//设置GET请求的参数
NSDictionary *params=[[ NSDictionary alloc] initWithObjectsAndKeys: @"3", @"id", nil];
//发起GET请求
[manager GET: @"" parameters:params success:^(NSURLSessionDataTask *task, id responseObject) {
NSLog( @"HTML: %@", [[ NSString alloc]initWithData:responseObject encoding:NSUTF8StringEncoding]);
} failure:^(NSURLSessionDataTask *task, NSError *error) {
NSLog( @"visit error: %@",error);
}];

为了方便测试,这个示例里写了个简单的Web Server,httpServer.js

运行httpServer.js,需要安装node.js环境。然后:

sudo node httpServer

我使用了80端口,在Mac环境下是需要root权限的。

GET请求,获取JSON数据

方法和GET请求网页文本大同小异,个别参数或者设置对象上有不同:

      
      
1
2
3
4
5
6
7
8
9
10
11
12
13
      
      
NSURL *baseURL = [ NSURL URLWithString: @"http://localhost/"];
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
[config setHTTPAdditionalHeaders:@{ @"User-Agent" : @"My Browser"}];
AFHTTPSessionManager *manager=[[AFHTTPSessionManager alloc] initWithBaseURL:baseURL sessionConfiguration:config];
NSDictionary *params=[[ NSDictionary alloc] initWithObjectsAndKeys: @"8", @"id", nil];
[manager GET: @"/json" parameters:params success:^(NSURLSessionDataTask *task, id responseObject) {
NSDictionary * object=( NSDictionary *)responseObject;
NSLog( @"response message: %@",object[ @"message"]);
} failure:^(NSURLSessionDataTask *task, NSError *error) {
NSLog( @"visit error: %@",error);
}];

下载文件

AFNetworking API会返回NSURLSessionDownloadTask,可用于网络请求的取消、暂停和恢复。

其实上文中的GET方法也返回了这个对象,只不过下载文件时间可能会较长,有可能有这方面的需求。

      
      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
      
      
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
NSURL *URL = [ NSURL URLWithString: @"http://www.baidu.com/img/bdlogo.png"];
NSURLRequest *request = [ NSURLRequest requestWithURL:URL];
NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress: nil destination:^ NSURL *( NSURL *targetPath, NSURLResponse *response) {
NSURL *documentsDirectoryURL = [[ NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL: nil create: NO error: nil];
return [documentsDirectoryURL URLByAppendingPathComponent:[response suggestedFilename]];
} completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
NSLog( @"File downloaded to: %@", filePath);
uploadFilePath=filePath;
}];
[downloadTask resume];

使用AFNetworking加载图片

需要引入一下:

      
      
1
      
      
#import <UIImageView+AFNetworking.h>

然后,UIImageView就会有setImageWithURL供使用。

      
      
1
2
      
      
NSURL *URL = [ NSURL URLWithString: @"http://www.baidu.com/img/bdlogo.png"];
[imageView setImageWithURL:URL];

另外,提供了其他方法,可设置占位图片,图片下载成功和失败的处理,以及停止图片下载的方法。

      
      
1
2
3
4
      
      
setImageWithURL:
setImageWithURL :placeholderImage:
setImageWithURLRequest :placeholderImage :success :failure:
cancelImageRequestOperation

使用SDWebimage加载图片

SDWebImage,调用方式和AFNetworking类似,功能更强大,使用也很普及。

需要引入:

      
      
1
      
      
#import <SDWebImage/UIImageView+WebCache.h>

代码:

      
      
1
2
      
      
NSURL *URL = [ NSURL URLWithString: @"http://www.sogou.com/images/logo/new/sogou.png"];
[imageView sd_setImageWithURL:URL];

下面是完整的方法列表:

      
      
1
2
3
4
5
6
7
8
9
10
11
12
      
      
sd_imageURL
sd_setImageWithURL:
sd_setImageWithURL :placeholderImage:
sd_setImageWithURL :placeholderImage :options:
sd_setImageWithURL :completed:
sd_setImageWithURL :placeholderImage :completed:
sd_setImageWithURL :placeholderImage :options :completed:
sd_setImageWithURL :placeholderImage :options :progress :completed:
sd_setImageWithPreviousCachedImageWithURL :andPlaceholderImage :options :progress :completed:
sd_setAnimationImagesWithURLs:
sd_cancelCurrentImageLoad
sd_cancelCurrentAnimationImagesLoad

比AFNetworking选项更多一些,比如可以设置SDWebImageOptions

      
      
1
2
3
4
5
6
7
8
9
10
      
      
typedef NS_OPTIONS(NSUInteger, SDWebImageOptions ) {
SDWebImageRetryFailed = 1 < < 0,
SDWebImageLowPriority = 1 < < 1,
SDWebImageCacheMemoryOnly = 1 < < 2,
SDWebImageProgressiveDownload = 1 < < 3,
SDWebImageRefreshCached = 1 < < 4,
SDWebImageContinueInBackground = 1 < < 5,
SDWebImageHandleCookies = 1 < < 6,
SDWebImageAllowInvalidSSLCertificates = 1 < < 7,
};

还有:typedef void(^SDWebImageDownloaderProgressBlock)(NSInteger receivedSize, NSInteger expectedSize)

  • 可以用一组图片生成动画:sd_setAnimationImagesWithURLs
  • 使用之前的Cache先显示图片?sd_setImageWithPreviousCachedImageWithURL,这个我从字面意思理解,还没有使用
  • 有个process block,sd_setImageWithURL:placeholderImage:options:progress:completed:,可以获得receivedSizeexpectedSize字节参数,用来显示进程百分比

另外,iOS image caching. Libraries benchmark (SDWebImage vs FastImageCache),这篇文章测试和对比,结论也是SDWebimage更好一些。

AFNetworking上传文件

      
      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
      
      
NSMutableURLRequest *request = [[AFHTTPRequestSerializer serializer] multipartFormRequestWithMethod: @"POST" URLString: @"http://localhost/upload" parameters: nil constructingBodyWithBlock:^( id<AFMultipartFormData> formData) {
[formData appendPartWithFileURL:uploadFilePath name: @"file" fileName: @"filename.jpg" mimeType: @"image/jpeg" error: nil];
} error: nil];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
NSProgress *progress = nil;
NSURLSessionUploadTask *uploadTask = [manager uploadTaskWithStreamedRequest:request progress:&progress completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
if (error) {
NSLog( @"Error: %@", error);
} else {
NSLog( @"%@ %@", response, responseObject);
}
}];
[uploadTask resume];

可以通过NSProgress获取上传进度(具体怎么做呢?)

使用OHHTTPStubs伪造HTTP响应

OHHTTPStubs,可用来伪造HTTP响应,这样不依赖服务器端,iOS的开发人员就可以测试网络服务了。

这个API,同时支持:

  • NSURLConnection
  • NSURLSession

不过,有个问题需要注意,如果App要上AppStore,是不能连接OHHTTPStubs的。

下面说下怎么使用,先看代码:

      
      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
      
      
NSString *baseUrl= @"http://localhost";
//针对http://locahost/json请求的mock
[OHHTTPStubs stubRequestsPassingTest:^ BOOL( NSURLRequest *request) {
NSDictionary *params=[ NSDictionary objectsFromURLQueryString:request .URL .query];
NSLog( @"id: %@",params[ @"id"]);
return [[request .URL absoluteString] rangeOfString:[ NSString stringWithFormat: @"%@/json",baseUrl]] .location== 0;
} withStubResponse:^OHHTTPStubsResponse*( NSURLRequest *request) {
NSLog( @"reqeust: %@",request);
NSString* fixture = OHPathForFileInBundle( @"test.json", nil);
return [[OHHTTPStubsResponse responseWithFileAtPath:fixture
statusCode: 200 headers:@{ @"Content-Type": @"text/json"}
]requestTime: 0 responseTime: 0];
}];

基本思路是,调用方法,通过2个回调(Block)实现对指定HTTP请求的响应伪造:

  • 是否是要拦截的请求
  • 拦截后,创建一个响应

在上述代码里还演示了:

  • 如何从URL中提取GET请求的参数,这里用到了:URLQueryToCocoa
  • 使用本地文件作为JSON数据,加入到HTTP响应中
  • 可以设置请求和响应的延时,requestTime:0 responseTime:0,这个相当有用

还可以用于伪造图片的响应,测试了一下,上述的AFNetworking以及SDWebimage都有效。

      
      
1
2
3
4
5
6
7
8
9
10
      
      
//GET image with sdwebimage
[OHHTTPStubs stubRequestsPassingTest:^ BOOL( NSURLRequest *request) {
return [[request .URL absoluteString] isEqualToString: @"http://www.sogou.com/images/logo/new/sogou.png"];
} withStubResponse:^OHHTTPStubsResponse*( NSURLRequest *request) {
NSLog( @"reqeust: %@",request);
NSString* fixture = OHPathForFileInBundle( @"taobao.png", nil);
return [[OHHTTPStubsResponse responseWithFileAtPath:fixture
statusCode: 200 headers:@{ @"Content-Type": @"image/png"}
]requestTime: 0 responseTime: 0];
}];

测试的时候,要注意,之前可能是通过真实网络获取的,因此会有缓存。需要把App删除,重新安装测试。

应该能看到类似下面的效果(使用的时本地图片了):

OHHTTPStubs这些代码,只需在App启动加载一次即可,可写在AppDelegate中:

      
      
1
2
3
      
      
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[[AFNetworkReachabilityManager sharedManager] startMonitoring];
[HttpMock initMock];

代码屏蔽掉,自然就使用真实网络了。

编译正式使用代码的时候,可以考虑条件编译。

AFNetworking的网络监控API

提供的AFNetworkReachabilityManager可以单独使用,很方便,用于监控网络变化。

比如,可以在App启动后执行下面操作,启动监控器:

      
      
1
2
      
      
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[[AFNetworkReachabilityManager sharedManager] startMonitoring];

在ViewController中:

      
      
1
2
3
4
5
6
      
      
-(void)viewDidLoad
{
[[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock :^(AFNetworkReachabilityStatus status) {
NSLog(@ "Reachability: %@", AFStringFromNetworkReachabilityStatus(status));
}];
}

监听网络变化,做出相应的操作,比如弹出提示框。

正式使用时:

  • 可考虑在AppDelegate中setReachabilityStatusChangeBlock,当状态变化后,通过NSNotification发出通知
  • 在各个ViewController的viewDidAppearviewWillDisappear中监听和取消监听通知

这是设想,还没有付诸实施,也许还有问题。

不过至少不应该像本例中的,在ViewController中使用setReachabilityStatusChangeBlock


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值