请选择 进入手机版 | 继续访问电脑版

AFNetworking

AFNetworking

NSURLSessionTaskDelegate
代理4:
[Objective-C] 纯文本查看 复制代码
//被服务器重定向的时候调用
- (void)URLSession:(NSURLSession *)session
              task:(NSURLSessionTask *)task
willPerformHTTPRedirection:(NSHTTPURLResponse *)response
        newRequest:(NSURLRequest *)request
 completionHandler:(void (^)(NSURLRequest *))completionHandler
{
    NSURLRequest *redirectRequest = request;

    // step1. 看是否有对应的user block 有的话转发出去,通过这4个参数,返回一个NSURLRequest类型参数,request转发、网络重定向.
    if (self.taskWillPerformHTTPRedirection) {
        //用自己自定义的一个重定向的block实现,返回一个新的request。
        redirectRequest = self.taskWillPerformHTTPRedirection(session, task, response, request);
    }

    if (completionHandler) {
        // step2. 用request重新请求
        completionHandler(redirectRequest);
    }
}

  • 一开始我以为这个方法是类似NSURLProtocol,可以在请求时自己主动的去重定向request,后来发现不是,这个方法是在服务器去重定向的时候,才会被调用。为此我写了段简单的PHP测了测:
[PHP] 纯文本查看 复制代码
<?php
defined('BASEPATH') OR exit('No direct script access allowed');

class Welcome extends CI_Controller {
    public function index()
    {
        header("location: http://www.huixionghome.cn/");
    }
}

证实确实如此,当我们服务器重定向的时候,代理就被调用了,我们可以去重新定义这个重定向的request。
  • 关于这个代理还有一些需要注意的地方:
    此方法只会在default session或者ephemeral session中调用,而在background session中,session task会自动重定向。

这里指的模式是我们一开始Init的模式:
[Objective-C] 纯文本查看 复制代码
if (!configuration) {
    configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
}
self.sessionConfiguration = configuration;
这个模式总共分为3种:

对于NSURLSession对象的初始化需要使用NSURLSessionConfiguration,而NSURLSessionConfiguration有三个类工厂方法:
+defaultSessionConfiguration 返回一个标准的 configuration,这个配置实际上与 NSURLConnection 的网络堆栈(networking stack)是一样的,具有相同的共享 NSHTTPCookieStorage,共享 NSURLCache 和共享NSURLCredentialStorage。
+ephemeralSessionConfiguration 返回一个预设配置,这个配置中不会对缓存,Cookie 和证书进行持久性的存储。这对于实现像秘密浏览这种功能来说是很理想的。
+backgroundSessionConfiguration:(NSString *)identifier 的独特之处在于,它会创建一个后台 session。后台 session 不同于常规的,普通的 session,它甚至可以在应用程序挂起,退出或者崩溃的情况下运行上传和下载任务。初始化时指定的标识符,被用于向任何可能在进程外恢复后台传输的守护进程(daemon)提供上下文。

代理5:
[Objective-C] 纯文本查看 复制代码
//https认证
- (void)URLSession:(NSURLSession *)session
              task:(NSURLSessionTask *)task
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
 completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
{
    NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
    __block NSURLCredential *credential = nil;

    if (self.taskDidReceiveAuthenticationChallenge) {
        disposition = self.taskDidReceiveAuthenticationChallenge(session, task, challenge, &credential);
    } else {
        if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
            if ([self.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {
                disposition = NSURLSessionAuthChallengeUseCredential;
                credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
            } else {
                disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
            }
        } else {
            disposition = NSURLSessionAuthChallengePerformDefaultHandling;
        }
    }

    if (completionHandler) {
        completionHandler(disposition, credential);
    }
}

  • 鉴于篇幅,就不去贴官方文档的翻译了,大概总结一下:
    之前我们也有一个https认证,功能一样,执行的内容也完全一样。
  • 区别在于这个是non-session-level级别的认证,而之前的是session-level级别的。
  • 相对于它,多了一个参数task,然后调用我们自定义的Block会多回传这个task作为参数,这样我们就可以根据每个task去自定义我们需要的https认证方式。
代理6:
[Objective-C] 纯文本查看 复制代码
//当一个session task需要发送一个新的request body stream到服务器端的时候,调用该代理方法。

- (void)URLSession:(NSURLSession *)session
              task:(NSURLSessionTask *)task
 needNewBodyStream:(void (^)(NSInputStream *bodyStream))completionHandler
{

    NSInputStream *inputStream = nil;

    //有自定义的taskNeedNewBodyStream,用自定义的,不然用task里原始的stream
    if (self.taskNeedNewBodyStream) {
        inputStream = self.taskNeedNewBodyStream(session, task);
    } else if (task.originalRequest.HTTPBodyStream && [task.originalRequest.HTTPBodyStream conformsToProtocol:@protocol(NSCopying)]) {
        inputStream = [task.originalRequest.HTTPBodyStream copy];
    }

    if (completionHandler) {
        completionHandler(inputStream);
    }
}
  • 该代理方法会在下面两种情况被调用:
    • 如果task是由uploadTaskWithStreamedRequest:创建的,那么提供初始的request body stream时候会调用该代理方法。
    • 因为认证挑战或者其他可恢复的服务器错误,而导致需要客户端重新发送一个含有body stream的request,这时候会调用该代理。

代理7:
[Objective-C] 纯文本查看 复制代码
/*
 //周期性地通知代理发送到服务器端数据的进度。
 */

- (void)URLSession:(NSURLSession *)session
              task:(NSURLSessionTask *)task
   didSendBodyData:(int64_t)bytesSent
    totalBytesSent:(int64_t)totalBytesSent
totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
{
     // 如果totalUnitCount获取失败,就使用HTTP header中的Content-Length作为totalUnitCount

    int64_t totalUnitCount = totalBytesExpectedToSend;
    if(totalUnitCount == NSURLSessionTransferSizeUnknown) {
        NSString *contentLength = [task.originalRequest valueForHTTPHeaderField:@"Content-Length"];
        if(contentLength) {
            totalUnitCount = (int64_t) [contentLength longLongValue];
        }
    }

    if (self.taskDidSendBodyData) {
        self.taskDidSendBodyData(session, task, bytesSent, totalBytesSent, totalUnitCount);
    }
}
  • 就是每次发送数据给服务器,会回调这个方法,通知已经发送了多少,总共要发送多少。
  • 代理方法里也就是仅仅调用了我们自定义的Block而已。
原文的话:
其实写了这么多,还没有讲到真正重要的地方,但是因为已经接近简书最大篇幅,所以只能先在这里结个尾了。
如果能看到这里,说明你是个非常有耐心,非常好学,非常nice的iOS开发。楼主为你点个赞。那么相信你也不吝啬手指动一动,给本文点个喜欢...顺便关注一下楼主...毕竟写了这么多...也很辛苦...咳咳,我不小心说出心声了么?
最后,万一如果本文有人转载,麻烦注明出处~谢谢!

看的细心的人:
HEALTHYbaby
6楼 · 2016.12.05 15:31

//对传过来的BaseUrl进行处理,截去url最后的/
if ([[url path] length] > 0 && ![[url absoluteString] hasSuffix:@"/"]) {
url = [url URLByAppendingPathComponent:@""];
}

这里的意思应该是有路径且最后不包含"/"。
这里应该是为传过来的url加上@"/",而不是截去最后的@"/"
1人赞
涂耀辉:抱歉:smile:这个注释年头有点久,笔误。。看的很细致:+1::+1:
lyxia_ios
11楼 · 2016.12.08 09:34
是否笔误:
“其实初始化方法都调用父类的初始化方法。父类也就是AF3.x最最核心的类AFHTTPSessionManager。”
这处的父类是不是应该是:AFURLSessionManager ??

涂耀辉:@lyxia_ios 抱歉,是笔误...感谢提醒~已更正 :pray:
文 /涂耀辉(简书作者)
原文链接:http://www.jianshu.com/p/856f0e26279d





举报 使用道具
| 回复

共 0 个关于本帖的回复 最后回复于 2017-1-11 23:14

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

本文内容不够精彩,我要自己发布

发布新帖

推荐阅读

    拥有的,不仅是技术!还有...
    联系 Email: support.36ji@qq.com

    • 关注酷站官方微博
      了解最新动态

    • 关注酷站微信公众号
      这里有好玩的讯息

    • 加入酷站交流群
      不断在这里成长

    © 2014-2017 36ji网络科技有限公司 . All rights reserved.
    京ICP备14001609号

    Archiver|    
    Powered by Discuz! X3.2 © 2001-2013 Comsenz Inc.
    快速回复 返回顶部 返回列表