美文网首页
AFNetworking-AFURLSessionManager

AFNetworking-AFURLSessionManager

作者: Code_人生 | 来源:发表于2019-09-28 21:31 被阅读0次

一、manager初始化

  • manager是类方法,工厂设计模式,不是单例哦
  • 线程:2.0 AF 建立在常驻线程,3.0 在Runloop NSOperationQueue
    NSString *urlStr = @"https://api.douban.com/v2/movie/top250";
    NSDictionary *dic = @{@"start":@(1),
                          @"count":@(5)
                          };
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    [manager GET:urlStr parameters:dic progress:^(NSProgress * _Nonnull downloadProgress) {
        
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        NSLog(@"%@",responseObject);
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSLog(@"%@",error);
    }];
  • 1、点击manager
+ (instancetype)manager {
    return [[[self class] alloc] initWithBaseURL:nil];
}

- (instancetype)init {
    return [self initWithBaseURL:nil];
}

- (instancetype)initWithBaseURL:(NSURL *)url {
    return [self initWithBaseURL:url sessionConfiguration:nil];
}

- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
    return [self initWithBaseURL:nil sessionConfiguration:configuration];
}
  • 2.1、调用父类的方法
  • 2.2、给url添加“/”。重定向,再请求一次,浪费带宽;表示目录,信息拼接,路由。SEO(Search Engine Optimization):汉译为搜索引擎优化。
  • 2.3、给requestSerializer、responseSerializer设置默认值
- (instancetype)initWithBaseURL:(NSURL *)url
           sessionConfiguration:(NSURLSessionConfiguration *)configuration
{
    //调用父类初始化方法
    self = [super initWithSessionConfiguration:configuration];
    if (!self) {
        return nil;
    }

    // Ensure terminal slash for baseURL path, so that NSURL +URLWithString:relativeToURL: works as expected
    /*
     为了确保NSURL +URLWithString:relativeToURL: works可以正确执行,在baseurlpath的最后添加‘/’
     */
    //url有值且没有‘/’,那么在url的末尾添加‘/’
    // 解释1: 防止重定向 -- www.baidu.com 调用2次 浪费带宽
    // 解释2: 表示目录 信息的拼接 路由
    // 解释3: SEO 搜索引擎优化
    if ([[url path] length] > 0 && ![[url absoluteString] hasSuffix:@"/"]) {
        url = [url URLByAppendingPathComponent:@""];
    }
    self.baseURL = url;
    //给requestSerializer、responseSerializer设置默认值
    self.requestSerializer = [AFHTTPRequestSerializer serializer];
    self.responseSerializer = [AFJSONResponseSerializer serializer];

    return self;
}
  • 3.1、初始化一个session
  • 3.2、给manager的属性设置初始值
- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration {
    self = [super init];
    if (!self) {
        return nil;
    }

    //设置默认的configuration,配置我们的session
    if (!configuration) {
        configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    }

    //持有configuration
    self.sessionConfiguration = configuration;

    //设置为delegate的操作队列并发的线程数量1,也就是串行队列
    self.operationQueue = [[NSOperationQueue alloc] init];
    self.operationQueue.maxConcurrentOperationCount = 1;

    /*
     -如果完成后需要做复杂(耗时)的处理,可以选择异步队列
     -如果完成后直接更新UI,可以选择主队列
     [NSOperationQueue mainQueue]
     */
    
    self.session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue];

    //默认为json解析
    self.responseSerializer = [AFJSONResponseSerializer serializer];

    //设置默认证书 无条件信任证书https认证
    self.securityPolicy = [AFSecurityPolicy defaultPolicy];

#if !TARGET_OS_WATCH
    //网络状态监听
    self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];
#endif

    //delegate= value taskid = key
    self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init];

    //使用NSLock确保线程安全
    self.lock = [[NSLock alloc] init];
    self.lock.name = AFURLSessionManagerLockName;

    //异步的获取当前session的所有未完成的task。其实讲道理来说在初始化中调用这个方法应该里面一个task都不会有
    //后台任务重新回来初始化session,可能就会有先前的任务
    //https://github.com/AFNetworking/AFNetworking/issues/3499
    [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
        for (NSURLSessionDataTask *task in dataTasks) {
            [self addDelegateForDataTask:task uploadProgress:nil downloadProgress:nil completionHandler:nil];
        }

        for (NSURLSessionUploadTask *uploadTask in uploadTasks) {
            [self addDelegateForUploadTask:uploadTask progress:nil completionHandler:nil];
        }

        for (NSURLSessionDownloadTask *downloadTask in downloadTasks) {
            [self addDelegateForDownloadTask:downloadTask progress:nil destination:nil completionHandler:nil];
        }
    }];

    return self;
}

二、request方法封装

  • request : 请求行 + 请求头 + 请求体
  • 请求头
  • 请求头参数
- (NSURLSessionDataTask *)GET:(NSString *)URLString
                   parameters:(id)parameters
                     progress:(void (^)(NSProgress * _Nonnull))downloadProgress
                      success:(void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success
                      failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure
{

    //返回一个task,然后开始网络请求
    NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"GET"
                                                        URLString:URLString
                                                       parameters:parameters
                                                   uploadProgress:nil
                                                 downloadProgress:downloadProgress
                                                          success:success
                                                          failure:failure];

    //开始网络请求
    [dataTask resume];

    return dataTask;
}
  • 点击dataTaskWithHTTPMethod...
//1.生成request,2.通过request生成task
- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
                                       URLString:(NSString *)URLString
                                      parameters:(id)parameters
                                  uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgress
                                downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgress
                                         success:(void (^)(NSURLSessionDataTask *, id))success
                                         failure:(void (^)(NSURLSessionDataTask *, NSError *))failure
{
    NSError *serializationError = nil;
    /*
     1.先调用AFHTTPRequestSerializer的requestWithMethod函数构建request
     2.处理request构建产生的错误 – serializationError
     //relativeToURL表示将URLString拼接到baseURL后面

     */
    NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
    if (serializationError) {
        if (failure) {
            //http://fuckingclangwarnings.com/#semantic
            //xcode忽略编译器的警告,diagnostic:诊断的
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
            //completionQueue不存在返回dispatch_get_main_queue
            dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
                failure(nil, serializationError);
            });
#pragma clang diagnostic pop
        }

        return nil;
    }

    //此时的request已经将参数拼接在url后面
    __block NSURLSessionDataTask *dataTask = nil;
    dataTask = [self dataTaskWithRequest:request
                          uploadProgress:uploadProgress
                        downloadProgress:downloadProgress
                       completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
        if (error) {
            if (failure) {
                failure(dataTask, error);
            }
        } else {
            if (success) {
                success(dataTask, responseObject);
            }
        }
    }];

    return dataTask;
}
  • 点击requestWithMethod...
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
                                 URLString:(NSString *)URLString
                                parameters:(id)parameters
                                     error:(NSError *__autoreleasing *)error
{
    //断言如果nil,直接打印出来
    NSParameterAssert(method);
    NSParameterAssert(URLString);

    //我们传进来的是一个字符串,在这里它帮你转成url
    NSURL *url = [NSURL URLWithString:URLString];

    NSParameterAssert(url);

    NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:url];
    //设置请求方式(get、post、put。。。)
    mutableRequest.HTTPMethod = method;

    //将request的各种属性遍历,给NSMutableURLRequest自带的属性赋值
    for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
        //给设置过得的属性,添加到request(如:timeout)
        if ([self.mutableObservedChangedKeyPaths containsObject:keyPath]) {
            //通过kvc动态的给mutableRequest添加value
            [mutableRequest setValue:[self valueForKeyPath:keyPath] forKey:keyPath];
        }
    }

    //将传入的参数进行编码,拼接到url后并返回 coount=5&start=1
    mutableRequest = [[self requestBySerializingRequest:mutableRequest withParameters:parameters error:error] mutableCopy];
    NSLog(@"request'''''''''%@",mutableRequest);

    return mutableRequest;
}
  • 点击requestBySerializingRequest...
- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request
                               withParameters:(id)parameters
                                        error:(NSError *__autoreleasing *)error
{
    NSParameterAssert(request);

    NSMutableURLRequest *mutableRequest = [request mutableCopy];

    //给mutableRequest.headfiled赋值
    /*
      1.请求行(状态行):get,url,http协议1.1
     2.请求头:conttent-type,accept-language
     3.请求体:get/post get参数拼接在url后面 post数据放在body
    
     */
    [self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) {
        if (![request valueForHTTPHeaderField:field]) {
            [mutableRequest setValue:value forHTTPHeaderField:field];
        }
    }];

    //将我们传入的字典转成字符串
    NSString *query = nil;
    if (parameters) {
        //自定义的解析方式
        if (self.queryStringSerialization) {
            NSError *serializationError;
            query = self.queryStringSerialization(request, parameters, &serializationError);

            if (serializationError) {
                if (error) {
                    *error = serializationError;
                }

                return nil;
            }
        } else {
            //默认解析方式,dic-   count=5&start=1
            switch (self.queryStringSerializationStyle) {
                case AFHTTPRequestQueryStringDefaultStyle:
                    //将parameters传入这个c函数
                    query = AFQueryStringFromParameters(parameters);
                    break;
            }
        }
    }

    //count=5&start=1
    NSLog(@"query:%@",query);
    //最后判断该request中是否包含了GET、HEAD、DELETE(都包含在HTTPMethodsEncodingParametersInURI)。因为这几个method的query是拼接到url后面的。而POST、PUT是把query拼接到http body中的。
    if ([self.HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) {
        if (query && query.length > 0) {
            mutableRequest.URL = [NSURL URLWithString:[[mutableRequest.URL absoluteString] stringByAppendingFormat:mutableRequest.URL.query ? @"&%@" : @"?%@", query]];
        }
    } else {
        // #2864: an empty string is a valid x-www-form-urlencoded payload
        if (!query) {
            query = @"";
        }
        //函数会判断request的Content-Type是否设置了,如果没有,就默认设置为application/x-www-form-urlencoded
        //application/x-www-form-urlencoded是常用的表单发包方式,普通的表单提交,或者js发包,默认都是通过这种方式
        if (![mutableRequest valueForHTTPHeaderField:@"Content-Type"]) {
            [mutableRequest setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
        }
        //设置请求体
        [mutableRequest setHTTPBody:[query dataUsingEncoding:self.stringEncoding]];
    }

    return mutableRequest;
}

三、task与代理(AFURLSessionManagerTaskDelegate)的关系

  • manager -> session -> task -> delegate -> /weak/ -> manager
self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;

存在了mutableTaskDelegatesKeyedByTaskIdentifier字典中,task.taskIdentifier为key,delegate为value

四、manager与代理(AFURLSessionManagerTaskDelegate)的关系

AFURLSessionManagerTaskDelegate类 中 有AFURLSessionManager属性
@property (nonatomic, weak) AFURLSessionManager *manager;

相关文章

网友评论

      本文标题:AFNetworking-AFURLSessionManager

      本文链接:https://www.haomeiwen.com/subject/gszcyctx.html