nsurlsessiond的delegate为什么是retain

iOS开发 GET、POST请求方法:NSURLSession篇 - 推酷
iOS开发 GET、POST请求方法:NSURLSession篇
NSURLConnection,在iOS 9被宣布弃用,本文不使用NSURLConnection进行网络编程,有兴趣的童鞋可以参考:
介绍:NSURLSession,为iOS7中的新网络接口,是在2013年的WWDC上,由Apple提出的NSURLConnection继任者的:NSURLSession。
NSURLSession,与NSURLConnection是并列的,且可以支持后台相关的网络操作的新特性;与NSURLConnection不同的是,NSURLSession把NSURLConnection替换成NSURLSession, NSURLSessionConfiguration,NSURLSessionTask。
NSURLSession一般分别两部操作:第一,通过NSURLSession的实例创建task;第二,执行task;
而NSURLSessionTask,也就是task,可以把它当作所谓的任务。
NSURLSessionTask是一个抽象子类,它有三个具体的子类是可以直接使用的:NSURLSessionDataTask,NSURLSessionUploadTask和NSURLSessionDownloadTask。这三个类应用的三个基本网络任务:获取数据、上传文件、下载文件。与数据有关的NSURLSessionDataTask也可以胜任上传下载的任务,所以经常使用到。
————示例————–
一、GET方法
// 1.创建一个网络路径
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@&http://172.16.2.254/php/phonelogin?yourname=%@&yourpas=%@&btn=login&,yourname,yourpass]];
// 2.创建一个网络请求
NSURLRequest *request =[NSURLRequest requestWithURL:url];
// 3.获得会话对象
NSURLSession *session = [NSURLSession sharedSession];
// 4.根据会话对象,创建一个Task任务:
NSURLSessionDataTask *sessionDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSLog(@&从服务器获取到数据&);
对从服务器获取到的数据data进行相应的处理:
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:(NSJSONReadingMutableLeaves) error:nil];
// 5.最后一步,执行任务(resume也是继续执行):
[sessionDataTask resume];
二、POST方法
// 1.创建一个网络路径
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@&http://172.16.2.254/php/phonelogin&]];
// 2.创建一个网络请求,分别设置请求方法、请求参数
NSMutableURLRequest *request =[NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @&POST&;
NSString *args = [NSString stringWithFormat:@&yourname=%@&yourpass=%@&btn=login&,yourname,yourpass];
request.HTTPBody = [args dataUsingEncoding:NSUTF8StringEncoding];
// 3.获得会话对象
NSURLSession *session = [NSURLSession sharedSession];
// 4.根据会话对象,创建一个Task任务
NSURLSessionDataTask *sessionDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSLog(@&从服务器获取到数据&);
对从服务器获取到的数据data进行相应的处理.
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:(NSJSONReadingMutableLeaves) error:nil];
//5.最后一步,执行任务,(resume也是继续执行)。
[sessionDataTask resume];
三、NSURLSessionDataDelegate代理方法
从前面两种方法中,我们都可以看出,相比NSURLConnection,NSURLSession提供了block方式处理返回数据的简便方式,但是,如果项目需要在网络请求数据的过程中,要做进一步的处理的话,需要调用NSURLSession的代理方法。
通常,使用代理方法需要先设置代理对象,但是通过查看NSURLSessionDataDelegate文档,我们可以看到如下,代理属性delegate为只读状态。
@property (nullable, readonly, retain)
那么我们需要怎样设置代理对象呢?下面我们通过代码演示关于代理方法的使用:
首先在文件开头添加代理协议,
@interface ViewController : UIViewController
//遵循代理协议
主方法的编写如下:
// 1.delegateQueue参数表示协议方法将会在(NSOperationQueue)队列里面执行。(session的delegate属性是只读的,所以使用如下方法设置代理。)
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]
delegate:self
delegateQueue:[[NSOperationQueue alloc] init]];
// 2.创建任务(因为要使用代理方法,就不需要block方式的初始化了)
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@&http://172.16.2.254/php/phonelogin?yourname=%@&yourpass=%@&btn=login&,yourname,yourpass]];
NSURLSessionDataTask *task = [session dataTaskWithRequest:[NSURLRequest requestWithURL:url]];
// 3.执行任务
[task resume];
关于代理行为:
#pragma mark -- NSURLSessionDataDelegate// 1.接收到服务器的响应
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler {
//【注意:此处需要允许处理服务器的响应,才会继续加载服务器的数据。 若在接收响应时需要对返回的参数进行处理(如获取响应头信息等),那么这些处理应该放在这个允许操作的前面。】
completionHandler(NSURLSessionResponseAllow);
// 2.接收到服务器的数据(此方法在接收数据过程会多次调用)
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
// 处理每次接收的数据,例如每次拼接到自己创建的数据receiveData
[self.receiveData appendData:data];
// 3.3.任务完成时调用(如果成功,error == nil)
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
if(error == nil){
请求完成,成功或者失败的处理
NSLog(@&请求失败:%@&,error);
四、NSURLSessionDownloadTask
1.NSURLSessionDownloadTask:文件下载任务
// 1.创建网路路径
NSURL *url = [NSURL URLWithString:@&http://172.16.2.254/php/phonelogin/image.png&] ;
// 2.获取会话
NSURLSession *session = [NSURLSession sharedSession];
// 3.根据会话,创建任务
NSURLSessionDownloadTask *task = [session downloadTaskWithURL:url completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
a.location是沙盒中tmp文件夹下的一个临时url,文件下载后会存到这个位置,由于tmp中的文件随时可能被删除,所以我们需要自己需要把下载的文件移动到其他地方:pathUrl.
b.response.suggestedFilename是从相应中取出文件在服务器上存储路径的最后部分,例如根据本路径为,最后部分应该为:“image.png”
NSString *path = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:response.suggestedFilename];
NSURL *pathUrl = [NSURL fileURLWithPath:path];
// 剪切文件
[[NSFileManager defaultManager] moveItemAtURL:location toURL:pathUrl error:nil];
// 4.启动任务
[task resume];
2.NSURLSessionDownloadDelegate代理方法:
首先添加协议
@interface ViewController : UIViewController
//遵循代理协议
代理方法如下:
// 1.每次写入调用(会调用多次)
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {
// 可在这里通过已写入的长度和总长度算出下载进度
CGFloat progress = 1.0 * totalBytesWritten / totalBytesExpectedToW NSLog(@&%f&,progress);
// 2.下载完成时调用
- (void)URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location {
这里的location也是一个临时路径,需要自己移动到需要的路径(caches下面)
NSString *filePath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:downloadTask.response.suggestedFilename];
[[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:filePath] error:nil];
// 3.请求成功/失败(如果成功,error为nil)
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
if(error == nil){
请求完成,成功或者失败的处理
NSLog(@&请求失败:%@&,error);
五、NSURLSessionUploadTask
1. NSURLSessionUploadTask上传文件的方式有2种:
NSURLSessionUploadTask *task =[[NSURLSession sharedSession] uploadTaskWithRequest:request fromFile:fileName
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {}];
POST方法:
[[NSURLSession sharedSession] uploadTaskWithRequest:request fromData:body
completionHandler:^(NSData data, NSURLResponse response, NSError *error) {
NSLog(@&-------%@&, [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil]);
不同的点,在于,用post方法需要添加网络路径的请求体body,而在实际开发中,上传文件一般使用post方式,更加安全可靠。
当然,对于使用NSURLSession开发的项目来说,还有更多的方式可以执行,需要我们在日常开发过程多多发现,以便更好地使用这个较新的网络接口,例如AFNetWorking2.0版本之后,就有了基于NSURLSession的封装运用,具体的有兴趣的童鞋可以去github了解下。
本文作者:伯乐在线 -
已发表评论数()
已收藏到推刊!
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
没有分页内容
图片无法显示
视频无法显示
与原文不一致经过多年的iOS开发, 现总结一下HTTP协议下的两大网络处理第三方框架的使用心得
首先来说下AFNetworking:
一、2大管理对象1.AFHTTPRequestOperationManager* 对NSURLConnection的封装
2.AFHTTPSessionManager* 对NSURLSession的封装
二、AFHTTPRequestOperationManager的具体使用1.创建管理者AFHTTPRequestOperationManager \*mgr = [AFHTTPRequestOperationManager manager];
2.封装请求参数
NSMutableDictionary \*params = [NSMutableDictionary dictionary];
params[@&username&] = @&哈哈&;
params[@&pwd&] = @&123&;
3.发送请求
NSString *url = @&http://localhost:8080/LWServer/login&;
[mgr POST:url parameters:params
success:^(AFHTTPRequestOperation \*operation, id responseObject) {
// 请求成功的时候调用这个block
NSLog(@&请求成功---%@&, responseObject);
} failure:^(AFHTTPRequestOperation \*operation, NSError *error) {
// 请求失败的时候调用调用这个block
NSLog(@&请求失败&);
// GET请求
[mgr GET:url parameters:params
success:^(AFHTTPRequestOperation \*operation, id responseObject) {
// 请求成功的时候调用这个block
NSLog(@&请求成功---%@&, responseObject);
} failure:^(AFHTTPRequestOperation \*operation, NSError *error) {
// 请求失败的时候调用调用这个block
NSLog(@&请求失败&);
三、对服务器返回数据的解析1.AFN可以自动对服务器返回的数据进行解析* 默认将服务器返回的数据当做JSON来解析
2.设置对服务器返回数据的解析方式1& 当做是JSON来解析(默认做法)* mgr.responseSerializer = [AFJSONResponseSerializer serializer];* responseObject的类型是NSDictionary或者NSArray
2& 当做是XML来解析* mgr.responseSerializer = [AFXMLParserResponseSerializer serializer];* responseObject的类型是NSXMLParser
3& 直接返回data* 意思是:告诉AFN不要去解析服务器返回的数据,保持原来的data即可* mgr.responseSerializer = [AFHTTPResponseSerializer serializer];
3.注意* 服务器返回的数据一定要跟responseSerializer对得上1& 服务器返回的是JSON数据* AFJSONResponseSerializer* AFHTTPResponseSerializer
2& 服务器返回的是XML数据* AFXMLParserResponseSerializer* AFHTTPResponseSerializer
3& 服务器返回的是其他数据* AFHTTPResponseSerializer
其次说下是asi-http-request:
一、发送请求的2个对象1.发送GET请求:ASIHttpRequest
2.发送POST请求:ASIFormDataRequest* 设置参数
// 同一个key只对应1个参数值,适用于普通“单值参数”
- (void)setPostValue:(id &NSObject&)value forKey:(NSString \*)key
// 同一个key(同一个参数名),会对应多个参数值,适用于“多值参数”
- (void)addPostValue:(id &NSObject&)value forKey:(NSString \*)key
二、发送请求1.同步请求* startSynchronous
2.异步请求* startAsynchronous
三、监听请求的过程1.如何监听请求过程1& 为代理,遵守&ASIHTTPRequestDelegate&协议,实现协议中的代理方法
request.delegate =
- (void)requestStarted:(ASIHTTPRequest *)
- (void)request:(ASIHTTPRequest *)request didReceiveResponseHeaders:(NSDictionary *)responseH
- (void)request:(ASIHTTPRequest *)request didReceiveData:(NSData *)
- (void)requestFinished:(ASIHTTPRequest *)
- (void)requestFailed:(ASIHTTPRequest *)
2& 成为代理,不遵守&ASIHTTPRequestDelegate&协议,自定义代理方法
request.delegate =
[request setDidStartSelector:@selector(start:)];
[request setDidFinishSelector:@selector(finish:)];
3& 设置block
[request setStartedBlock:^{
NSLog(@&setStartedBlock&);
[request setHeadersReceivedBlock:^(NSDictionary *responseHeaders) {
NSLog(@&setHeadersReceivedBlock--%@&, responseHeaders);
[request setDataReceivedBlock:^(NSData *data) {
NSLog(@&setDataReceivedBlock--%@&, data);
[request setCompletionBlock:^{
NSLog(@&setCompletionBlock&);
[request setFailedBlock:^{
NSLog(@&setFailedBlock&);
2.监听的使用注意* 如果同时设置了block和实现了代理方法,请求过程中,block和代理方法都会调用* 一般的调用顺序:代理方法 & block
3.如果实现了下面的代理方法,那么responseData\responseString就没有值
- (void)request:(ASIHTTPRequest *)request didReceiveData:(NSData *)
四、文件下载1.一般的下载1& 设置文件下载的保存路径
request.downloadDestinationPath =
2& 设置进度监听的代理(要想成为进度监听代理,最好遵守&ASIProgressDelegate&协议)
request.downloadProgressDelegate = self.progressV
2.断点下载(断点续传)1& 设置文件下载的临时路径
request.temporaryFileDownloadPath = tempF
2& 设置支持断点续传
request.allowResumeForFileDownloads = YES;
五、文件上传(设置文件参数)1.如果知道文件路径,最好就用这个方法(因为简单)
// ASI内部会自动识别文件的MIMEType
[request setFile:file forKey:@&file&];
[request addFile:file forKey:@&file&];
[request setFile:file withFileName:@&basic.pptx& andContentType:@&application/vnd.openxmlformats-officedocument.presentationml.presentation& forKey:@&file&];
2.如果文件数据是动态产生的,就用这个方法(比如刚拍照完获得的图片数据)
[request setData:data withFileName:@&test.png& andContentType:@&image/png& forKey:@&file&];
六、ASIHttpRequest的常见用法1.请求超时
@property (atomic, assign) NSTimeInterval timeOutS
2.获得错误信息
@property (atomic, retain) NSError *
3.获得响应数据
@property (atomic, assign,readonly) int responseStatusC
// 状态信息
@property (atomic, retain,readonly) NSString *responseStatusM
// 服务器返回的具体数据(NSString格式)
- (NSString *)responseS
// 服务器返回的具体数据(NSData格式)
- (NSData *)responseD
最后是重点内容,也是面试时经常会问的问题,两者的区别:
一、底层实现1& AFN的底层基于OC的NSURLConnection和NSURLSession2& ASI的底层基于纯C语言的CFNetwork框架3& ASI的运行性能 高于 AFN
二、对服务器返回的数据处理1& ASI没有直接提供对服务器数据处理的方式,直接返回data\string2& AFN提供了多种对服务器数据处理的方式* JSON处理* XML处理* 其他处理
三、监听请求的过程1& AFN提供了success和failure两个block来监听请求的过程(只能监听成功和失败)* success : 请求成功后调用* failure : 请求失败后调用
2& ASI提供了3套方案,每一套方案都能监听请求的完整过程(监听请求开始、接收到响应头信息、接受到具体数据、接受完毕、请求失败)* 成为代理,遵守协议,实现协议中的代理方法* 成为代理,不遵守协议,自定义代理方法* 设置block
四、在文件下载和文件上传的使用难易度1& AFN* 不容易监听下载进度和上传进度* 不容易实现断点续传* 一般只用来下载不大的文件
2& ASI* 非常容易实现下载和上传* 非常容易监听下载进度和上传进度* 非常容易实现断点续传* 下载或大或小的文件都行
五、ASI提供了更多的实用功能1& 控制圈圈要不要在请求过程中转2& 可以轻松地设置请求之间的依赖:每一个请求都是一个NSOperation对象3& 可以统一管理所有请求(还专门提供了一个叫做ASINetworkQueue来管理所有的请求对象)* 暂停\恢复\取消所有的请求* 监听整个队列中所有请求的下载进度和上传进度
以上就介绍了开发经验: 对AFN和ASI各自使用方法及区别的总结,包括了方面的内容,希望对IOS开发有兴趣的朋友有所帮助。
本文网址链接:/article/detail_119964.html
上一篇: 下一篇:Instrument调试内存泄漏-leaks
下载简书移动应用
写了46763字,被25人关注,获得了20个喜欢
Instrument调试内存泄漏-leaks
原文链接:http://blog.csdn.net/hello_hwc/article/details/前言:计划是7月份更新Instrument以及调试相关的博客,不过今天刚好遇到个内存泄漏的问题。五月份的数据持久化部分还有三篇左右没更新,六月份集中在多线程开发上。所以这里就简单写一下Instrument中leaks使用吧。如何打开LeaksXCode - Open Development Tool - Instruments
打开后会看到很多工具
选择 leaks打开
Allocations纪录了内存分配,用来优化内存使用的Leaks用来分析内存泄漏。ARC中引起的内存泄漏原因就是引用环。然后我们运行下一个小工程,这个工程是接下来要更新的一个异步网络下载tableview图片的前期雏形。这里要提到的是,我的博客写了这么多篇了,还是没有涉及到好的开源库,这部分后续我会写的。毕竟实际开发的过程中对开源库的选择也很重要,而且会大大提高效率。但是,我希望的是先把基础掌握好,这决定了理解的深度。看下效果图
乍一看还不错啊,tableview非常流畅,图片能够惰性下载(cell屏幕上再下载),这也是我想要的雏形。可是,好奇的用leaks分析一下
然后,我们打开leaks,看看错误出现在哪先选择Leaks和Leaks by Backtrace.这里可以看到那些对象内存泄漏了,泄漏了多少,这个就是简单看看,没有太多调试意义。
然后看看Call Tree,因为Call Tree会给我们大概的位置,有时候会给我们精确的位置,不过要看运气了。
然后,再又面选择Invert Call Tree和Hide System Library
然后,我们就知道大概内存泄漏的位置在NSOperation的子类这里了。然后双击上文图片中的任意一行,就会跳到代码处内存泄漏的地方(事实上,到这步,很多内存泄漏的问题都会被发现)
然后我们选择对ARC调试很有用的一个部分Circles & Roots,通过这个我们可以看到详细的ARC引用计数过程。点击Leaks图标可以选择
然后,我们看到如图小的红圈点击可以看到引用计数的详细信息(ARC 就是自动引用计数,计数为0,则对象会被释放)大的红圈可以绘制对象引用环的图,不过这里我们很不幸,没有直观的绘图出来。
然后,首先我们找一下我们自定义的对象,发现了DownloadImageOperation这个对象,这个对象是继承自NSOperation,正常在任务完成后就应该释放的。看来没有释放。为了确认,在DownloadImageOperation最后加上log代码,看看是否被释放-(void)dealloc{
NSLog(@"dealloc");}再运行下程序,果然没有被释放,这里肯定有问题。最后,我们在点击类似上图的小红圈中的剪头,详细的看下,这个对象的引用计数变化如图这里All 表示所有的引用计数变化Unpaired表示那些为成对的变化(成对就是leaks识别出了对应的+1,-1)By Group会把相关的变化分成一组,ByTime会按照顺序列出引用计数变化
我们选择Unpaired 和 ByGroup,看到如图
按照顺序看(最左边的标号)这里,引用计数是一,这是正确的,因为到这里正常就是应该是OperationQueue保存一个Operation的引用。于是,我们把正常的划掉
再继续看,download start 标号6和8是对应的,继续排除问题出现在这里(当然问题不可能出现在这里,这是系统的API,一定会释放,就是简单教大家如何看)
再看看,+1的还剩下标号7 和 11,7 是正常的为Operation分配线程,应当会+1,而11就是我们的问题所在了(大部分Delegate都不会使引用+1)。我们再看下文档@property(readonly, retain) id& NSURLSessionDelegate &delegate原来这个代理是retain啊,不是assign或者weak。所以形成了这样的引用环。
那么怎么办呢?有问题下看文档,我们看到图片中引起引用计数加一的是+ (NSURLSession*)sessionWithConfiguration:(NSURLSessionConfiguration*)configurationdelegate:(id)delegatedelegateQueue:(NSOperationQueue*)queue:看下文档,发现了这个地方
于是,我们要手动的去断开强引用,于是,我们手动去断开-(void)setOperationFinished{
[self.sessioninvalidateAndCancel];
[selfwillChangeValueForKey:@"isFinished"];
[selfwillChangeValueForKey:@"isExecuting"];
executing =NO;
finished =YES;
[selfdidChangeValueForKey:@"isExecuting"];
[selfdidChangeValueForKey:@"isFinished"];}再运行下看看,能够正常的Dealloc了0:28:36.814AsyncImageTableviewDemo[]dealloc0:28:36.954AsyncImageTableviewDemo[]dealloc用leaks分析,也没有内存泄漏了
总结:其实大多数问题在双击上文的代码部分就可以解决了,少数问题需要详细的分析ARC引用过程
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
选择支付方式:

我要回帖

更多关于 nsurlsessiond 的文章

 

随机推荐