NSURLRequest

网络请求的关键的就是NSURLRequest类,它的实例表示了请求报文实体以及请求的缓存策略等等,各种网络框架的最终目标都是把这个对象编译成为请求报文发送出去。下面用一个实例来说明它的用法。

//1、设置url和请求方法
NSString *urlString = [NSString stringWithFormat:@"http://maplecode.applinzi.com"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:[NSURL URLWithString:urlString]];
[request setHTTPMethod:@"POST"]; //2、设置报文头
NSString *contentType = [NSString stringWithFormat:@"text/xml"];
[request addValue:contentType forHTTPHeaderField: @"Content-Type"]; //3、设置报文体
NSMutableData *postBody = [NSMutableData data];
[postBody appendData:[[NSString stringWithFormat:@"id=%@&password=%@",@"admin02",@"admin02"] dataUsingEncoding:NSUTF8StringEncoding]];
[postBody appendData:[[NSString stringWithFormat:@"<Request Action=\"Login\">"] dataUsingEncoding:NSUTF8StringEncoding]];
[request setHTTPBody:postBody]; //4、发送请求报文并处理响应报文
NSHTTPURLResponse* urlResponse = nil;
NSError *error = [[NSError alloc] init];
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&urlResponse error:&error];
NSString *result = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];

注意到我们往往使用mutable的对象,方便修改。此外NSURLConnection类已经被建议废弃,现在可以使用NSURLSession创建task。

AFNetworking

1、基于NSOperation发送网络请求

本方法只适用于2.x版本的AFNetworking,新版本不再支持基于NSURLConnection的API。多线程往往用于实现异步网络请求,配合封装了通信接口的NSURLSession, CFNetwork, AFNetworking使用。下面重点介绍AFNetworking。

这个库集XML解析,Json解析,plist解析,数据流上传,下载,缓存等众多功能于一身,配合操作队列的用法如下:

NSString *str=[NSString stringWithFormat:@"https://alpha-api.app.net/stream/0/posts/stream/global"];
NSURL *url = [NSURL URLWithString:[str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSString *html = operation.responseString;
NSData* data=[html dataUsingEncoding:NSUTF8StringEncoding];
id dict=[NSJSONSerialization JSONObjectWithData:data options: error:nil];
NSLog(@"获取到的数据为:%@",dict);
}failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"发生错误!%@",error);
}];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation];

继承关系:AFHTTPRequestOperation : AFURLConnectionOperation : NSOperation,也就是说AFHTTPRequestOperation类和NSInvocationOperation的使用方法是一致的,把它加入操作队列就可以了。

2、新版AFNetworking基于NSURLSession

如果需要细致的控制请求报文,那么对于低版本的AFNetworking,可以使用AFHTTPClient类,它的实例表示了一个客户端,可以发出GET/POST请求。不过对于新版来说,这个类已经不存在了,可以用AFHTTPSessionManager来代替发送GET/POST请求,而且基于NSURLSession,还可以很方便的实现全局配置和文件上传下载。

@interface AFHTTPSessionManager
- (NSURLSessionDataTask *)GET:(NSString *)URLString
parameters:(id)parameters
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure;
- (NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(id)parameters
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure;
@end

可以看出,用这个类来发送请求,甚至不需要事先生成代表请求报文的NSURLRequest对象,简化了操作过程,也不需要基于NSOperation,但是需要基于新的类NSURLSessionTask,比如AFNetworking 3.x下:

NSURL *URL = [NSURL URLWithString:@"http://example.com/resources/123.json"];
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
[manager GET:URL.absoluteString parameters:nil progress:nil success:^(NSURLSessionTask *task, id responseObject) {
NSLog(@"JSON: %@", responseObject);
} failure:^(NSURLSessionTask *operation, NSError *error) {
NSLog(@"Error: %@", error);
}];

当下载任务结束后,怎么样在回调block中使用task实例和responseObject呢,我们只需要看一看一个task的创建和使用过程:

NSURLSession *session = [NSURLSession sharedSession];
[[session dataTaskWithURL:[NSURL URLWithString:londonWeatherUrl]
completionHandler:^(NSData *data,
NSURLResponse *response,
NSError *error) {
// handle response
}] resume];

一个task需要持有一个block的引用,作为数据传输结束的处理任务,并且可以调用resume方法启动下载任务。

原生NSURLSession

1、异步请求

依赖于第三方库并不总是希望的情况,比如作为一个有轻微强迫症的开发者,总是希望工程尽可能简单。NSURLSession类本身提供了非常清晰方便的接口,支持网络任务的resume, suspend, cancel, invalidate等等,支持文件直接上传下载,如果可以直接对NSURLSession进行简单封装的处理,就不愿意去依赖AFNetworking。注意头文件中的语句:

@property (readonly, retain) NSOperationQueue *delegateQueue;

这说明NSURLSession类的实例也是通过操作队列完成网络操作,并且以retain方式拥有一个操作队列作为委托对象,因此程序员并不需要在代码中创建NSOperationQueue对象了。

一个NSURLSession类的实例表示一系列会话的集合,程序员可以用一个NSURLSession的实例创造一个task对象来表示网络传输任务,正如上文中的代码片段可以建立一个异步网络请求,session可以维护这个task,并且session对象可以在网络传输结束后,把这个task的回调block放到delegateQueue中执行。

NSURLSession和NSURLSessionDataTask的关系,正是工厂设计模式的一个体现。

2、同步请求

如果程序员要以同步方式完成网络操作,过去通过 NSURLConnection.sendSynchronousRequest() 方法能同步请求数据。从iOS9起,苹果建议废除 NSURLConnection,使用 NSURLSession 代替 NSURLConnection,那么应该怎么办呢?使用信号、信号量就可以实现

public static func requestSynchronousData(request: NSURLRequest) -> NSData? {
var data: NSData? = nil
let semaphore: dispatch_semaphore_t = dispatch_semaphore_create()
let task = NSURLSession.sharedSession().dataTaskWithRequest(request, completionHandler: {
taskData, _, error -> () in
data = taskData
if data == nil, let error = error {print(error)}
dispatch_semaphore_signal(semaphore);
})
task.resume()
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
return data
}

或者用Objective-C的方式

@implementation NSURLSession (Synchronous)

+ (NSData *)requestSynchronousDataWithRequest:(NSURLRequest *)request{
__block NSData * data;
dispatch_semaphore_t sem = dispatch_semaphore_create();
void (^completion)(NSData * , NSURLResponse * , NSError * ) = ^(NSData * taskData, NSURLResponse * response, NSError * error){
data = taskData;
dispatch_semaphore_signal(sem);
};
NSURLSessionDataTask * task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:completion];
[task resume];
dispatch_semaphore_wait(sem,DISPATCH_TIME_FOREVER);
return data;
}
@end

由于completion block中的内容不会被主线程执行,而是被其他线程执行,在更新UI时可能会出问题甚至crash,比如当实例化UIWebView的时候,会发出错误:

Tried to obtain the web lock from a thread other than the main thread or the web thread.
This may be a result of calling to UIKit from a secondary thread. Crashing now...

用同步的方式就可以解决这个问题。或者就要使用GCD或者performSelector法某些代码放到主线程执行。

网络请求快捷方式

很多类可以直接获取JSON数据,图片数据等。在UI上,用SDWebImage模块中的分类实现了快捷方法,可以借助 [imageView setImageWithURL: placeholderImage:],可以直接请求需要显示的图片,并且有各种策略选项,减少冗长代码。

封装block

在特定业务环境下,网络请求往往存在大量重复代码,时常需要封装一些以block作为参数的函数。所以最后写一点关于block的感悟:

如果一个函数以block作为参数,那么这个函数的最终目标就是要生成这个block的参数。

这并不难于理解,因为block用于回调,我们构造通用函数,自然就是要构造出正确的值作为参数,然后才能调用传进来的block。同时,一个以block为参数的函数的形式上的返回值往往是不重要的,通常是void。理解这一点有助于实现封装避免重复代码。

Cocoa Touch(五):网络请求 NSURLSession/AFNetworking, GCD, NSURLResquest的更多相关文章

  1. IOS网络请求之AFNetWorking 3.x 使用

    前言: 计划把公司的网络请求与业务解耦,所以想着学习一下网络请求,最近学习了NSURLSession,今天来学习一下基于NSURLSession封装的优秀开源框架AFNetWorking 3.x,之前 ...

  2. iOS 网络请求NSURLSession

    iOS 7 和 Mac OS X 10.9 Mavericks 中一个显著的变化就是对 Foundation URL 加载系统的彻底重构. 现在已经有人在深入苹果的网络层基础架构的地方做研究了,所以我 ...

  3. IOS网络请求框架AFNetworking和ASIHttpRequest对比

    ASI基于CFNetwork框架开发,而AFN基于NSURL. ASI更底层,请求使用创建CFHTTPMessageRef进行,使用NSOperationQueue进行管理,ASIHTTPReques ...

  4. iOS开发之网络请求(基于AFNetworking的再封装)

    最近一直很忙也没有什么时间写博客了.放假了休息一下,就写一篇博客来总结一下最近做项目中出现过的问题吧!!! 首先,在项目中我的起到了什么作用,无非就是把美工(UI设计师)给我们的图显示出来,然后再和服 ...

  5. iOS之网络请求NSURLSession剖析

    2013年的WWDC大会上,苹果推出了NSURLSession,对Foundation URL加载系统进行了彻底的重构,提供了更丰富的API来处理网络请求,如:支持http2.0协议.直接把数据下载到 ...

  6. 网络请求工具--AFNetworking 分类: ios技术 2015-02-03 08:17 76人阅读 评论(0) 收藏

    在我们开发过程中,网络请求是必不可少的,对于网络框架,现在主流的大概只有三类:ASI框架: HTTP终结者(已经停止更新了),MKNetworkKit ,AFN.今天我就来浅谈一下这个AFN AFNe ...

  7. 移动开发在路上-- IOS移动开发 五 网络请求封装

    接着上次的讲,这次我们讲 网络请求的封装  打开创建的项目,让我们一起来继续完成他, 上次我们说到GET请求地址的拼接: 我们接着上次的继续完善: 下边我们要定义的是 block //定义block ...

  8. iOS网络请求基础

    这篇是关于网络请求的,结合公司的实际情况编写,如果有不同意见欢迎留言共同讨论. iOS在9.0之后彻底放弃了NSURLConnection,现在已经改用了NSURLSession进行网络请求.一般现在 ...

  9. CHNetRequest网络请求

    Paste JSON as Code • quicktype 软件的使用 iOS开发:官方自带的JSON使用 JSON 数据解析 XML 数据解析 Plist 数据解析 NetRequest 网络数据 ...

随机推荐

  1. Alpha阶段第1周/共2周 Scrum立会报告+燃尽图 03

    此作业要求参见:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2248 一.小组介绍 组长:刘莹莹 组员:朱珅莹 孙韦男 祝玮琦 王玉潘 ...

  2. 判断一棵树是否为二叉搜索树(二叉排序树) python

    输入一棵树,判断这棵树是否为二叉搜索树.首先要知道什么是排序二叉树,二叉排序树是这样定义的,二叉排序树或者是一棵空树,或者是具有下列性质的二叉树: (1)若左子树不空,则左子树上所有结点的值均小于它的 ...

  3. 本地代码同步到github

    1 设置 ssh 公钥信息 首先你要确保 github 账号设置了ssh 公钥信息.如果没有的话可以按照下面的方式设置: 前往 github 网站的 account settings, 依次点击 Se ...

  4. 把mac地址转换为标准mac地址

    把"00:90:8A:1D:30:51"转换成"00-90-8A-1D-30-51",如何格式错误,显示出格式错误的种类,有些不规范的转换成规范的格式,例如,& ...

  5. 6-18 Two Stacks In One Array(20 分)

    Write routines to implement two stacks using only one array. Your stack routines should not declare ...

  6. SD卡驱动学习

    https://blog.csdn.net/zqixiao_09/article/category/6163492 sd 协议解析: https://blog.csdn.net/g_salamande ...

  7. C#调用OCR组件识别图片文字

    图片识别的技术到几天已经很成熟了,只是相关的资料很少,为了方便在此汇总一下(C#实现),方便需要的朋友查阅,也给自己做个记号. 图片识别的用途:很多人用它去破解网站的验证码,用于达到自动刷票或者是批量 ...

  8. intellij idea 清除版本控制

    一.概述 intellij idea 再加入版本控制后,在工作空间中的项目文件都会纳入管理范围,这样idea左侧 "project视图" 中的项目及文件也会出现红色(可能其它颜色) ...

  9. 唯品会的Service Mesh三年进化史

    每种架构风格,都会因各公司面临的情况不同而有不同的实现路线,Service Mesh也不例外,比如江南白衣描述的唯品会的服务化体系开放服务平台OSP(Open Service Platform)走的S ...

  10. WCF 快速入门

    定义服务契约 构建HelloWCF应用的第一步是创建服务契约.契约式是表示消息应用外形的主要方式.对于外形,是指服务暴露的操作,使用的消息 schema和每个操作实现的消息交换模式(MEP).总之,契 ...