AFN多请求依赖(二)

作者: KODIE | 来源:发表于2017-07-04 21:08 被阅读55次

导读:AFN多请求依赖(一)

AFN多请求依赖(一)中解决的是如何将不同的AFN请求有序的进行请求:即第一个请求发出并且得到响应之后再次发出下一个请求并且得到响应,以此类推,最终在最后的一个请求得到响应之后执行刷新UI等操作。那么一中用到的技术主要是信号量。

但是有一个问题这样的异步AFN请求就相当于同步了,挨个挨个和主线程的同步没什么区别,耗费时间比较长,那么我们现在有一个需求就是当所有的请求发出之后,只要响应都接收到了那么就刷新UI,不需要排队挨个挨个去请求,但是一定要等到所有的请求请求到结果之后再刷新UI等操作,那么这个用到信号量肯定是不合适的,那么该怎么弄呢?

大家可以试一下其他的方式,比如说GCD的组之类的,但是我试过了不行,可能是我加的方式不对,大家有更好的方式还请简书留言,本文中使用的是使用一个Flag来标志,每次发送请求的时候Flag值+1;得到响应之后Flag值建-1;当用KVO监听到值为0时,刷新UI等操作,并且移除监听。

工具准备

  • AFN:这个可以手动导入也可以通过Cocoapods
  • BasicAFNTool:基于AFN封装的网络请求工具类
//BasicAFNTool.h
#import <Foundation/Foundation.h>

@interface BasicAFNTool : NSObject
+ (void)get:(NSString *)url
     params:(NSDictionary *)params
    success:(void(^)(id json))success
    failure:(void(^)(NSError *error))failure;

+ (void)post:(NSString *)url
      params:(NSDictionary *)params
     success:(void(^)(id json))success
     failure:(void(^)(NSError *error))failure;
@end

//BasicAFNTool.m
#import "BasicAFNTool.h"
#import "AFNetworking.h"

@implementation BasicAFNTool
+ (void)get:(NSString *)url
     params:(NSDictionary *)params
    success:(void(^)(id json))success
    failure:(void(^)(NSError *error))failure
{
    //创建请求管理者
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    manager.responseSerializer = [AFHTTPResponseSerializer serializer];
    //[manager.requestSerializer setValue:@"2" forHTTPHeaderField:@"User_Agent"];
    manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json",@"text/html",@"text/plain",@"image/jpeg", nil];
    
    //2发送请求
    [manager GET:url parameters:params progress:^(NSProgress * _Nonnull uploadProgress) {
        
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject)     {
        if (success) success(responseObject);
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        if (failure) failure(error);
    }];
}

+ (void)post:(NSString *)url
      params:(NSDictionary *)params
     success:(void(^)(id json))success
     failure:(void(^)(NSError *error))failure
{
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    //[manager.requestSerializer setValue:@"2" forHTTPHeaderField:@"User_Agent"];
    manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json",@"text/html",@"text/plain", nil];

    [manager POST:url parameters:params progress:^(NSProgress * _Nonnull uploadProgress) {
        
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject)     {
        if (success) success(responseObject);
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        if (failure) failure(error);
    }];
}
@end
  • KODURLService:URL链接的工具类
//KODURLService.h
#import <Foundation/Foundation.h>

@interface KODURLService : NSObject
+ (NSString *)urlString1;
+ (NSString *)urlString2;
+ (NSString *)urlString3;
@end
//KODURLService.m
#import "KODURLService.h"

@implementation KODURLService

+ (instancetype)defaultService {
    static KODURLService *instance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[self alloc] init];
    });
    return instance;
}
+ (NSString *)urlString1{
    NSString *urlString1 = @"https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=3495161387,2602242859&fm=23&gp=0.jpg";
    //NSString *urlString1 = @"http://github.com/qiruihua/bigimage/raw/master/011.jpg";
    return urlString1;
}
+ (NSString *)urlString2{
    NSString *urlString2 = @"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1493299941944&di=979daec634bebdcbb3c14792a2f1fe83&imgtype=0&src=http%3A%2F%2Fimg.taopic.com%2Fuploads%2Fallimg%2F121209%2F234928-12120Z0543764.jpg";
    return urlString2;
}
+ (NSString *)urlString3{
    NSString *urlString3 = @"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1493299941944&di=76092dbeceb09618622fd7993510c9fb&imgtype=0&src=http%3A%2F%2Fmvimg1.meitudata.com%2F55e2b8683d7464031.jpg";
    return urlString3;
}
@end

开干

#import "ViewController.h"
#import "KODURLService.h"
#import "BasicAFNTool.h"

@interface ViewController ()
@property(atomic,assign)NSInteger operationNum;//队列标识记录
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.operationNum = 0;
    
    [self addObserver:self forKeyPath:@"operationNum" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
    
    [self addBtn2];
}

- (void)addBtn2{
    UIButton *btn = [[UIButton alloc]init];
    btn.frame = CGRectMake(0, 300, 200, 50);
    CGPoint btnCenter = CGPointMake(self.view.center.x, btn.frame.origin.y + 25);
    btn.center = btnCenter;
    btn.backgroundColor = [UIColor orangeColor];
    [self.view addSubview:btn];
    [btn setTitle:@"外部操作封GCD信号" forState:UIControlStateNormal];
    [btn addTarget:self action:@selector(didClickBtn2) forControlEvents:UIControlEventTouchUpInside];
}

- (void)didClickBtn2{
    
    NSBlockOperation *blockOp1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"正在开始下载图片11111...");
        self.operationNum ++;
        [self basicAFNRequestWithUrlString:[KODURLService urlString1] message:@"dispatch_group_enter请求1" success:^(id json){
            NSLog(@"最终成功完成了请求1");
            
            self.operationNum --;
        } error:^(NSError *error){
            NSLog(@"最终失败完成了请求1,error = %@",error);
            self.operationNum --;
        }];
    }];
    
    NSBlockOperation *blockOp2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"正在开始下载图片22222...");
        self.operationNum ++;
        [self basicAFNRequestWithUrlString:[KODURLService urlString2] message:@"dispatch_group_enter请求2" success:^(id json){
            NSLog(@"最终成功完成了请求2");
            
            self.operationNum --;
        } error:^(NSError *error){
            NSLog(@"最终失败完成了请求2,error = %@",error);
            self.operationNum --;
        }];
    }];
    
    NSBlockOperation *blockOp3 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"正在开始下载图片33333...");
        self.operationNum ++;
        [self basicAFNRequestWithUrlString:[KODURLService urlString3] message:@"dispatch_group_enter请求3" success:^(id json){
            NSLog(@"最终成功完成了请求3");
            
            self.operationNum --;
        } error:^(NSError *error){
            NSLog(@"最终失败完成了请求3,error = %@",error);
            self.operationNum --;
        }];
    }];
    
    
    NSOperationQueue *queue = [[NSOperationQueue alloc]init];
    [queue setMaxConcurrentOperationCount:3];
    
    [blockOp2 addDependency:blockOp1];
    [blockOp3 addDependency:blockOp2];
    
    [queue addOperations:@[blockOp1,blockOp2,blockOp3] waitUntilFinished:NO];
}


#pragma mark - private
- (void)basicAFNRequestWithUrlString:(NSString *)urlString
                             message:(NSString *)message
                             success:(void(^)(id json))success
                               error:(void(^)(NSError *error))errorBlock
{
    NSLog(@"需要拿参%@",message);
    [BasicAFNTool get:urlString params:nil success:^(id json) {
        NSLog(@"%@",message);
        success(json);
    } failure:^(NSError *error) {
        NSLog(@"%@",message);
        errorBlock(error);
    }];
}

//监听
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
    if([keyPath isEqualToString:@"operationNum"] && object == self)
    {
        NSInteger new = [change[NSKeyValueChangeNewKey] integerValue];
        if (new == 0) {
            NSLog(@"任务执行完毕");
            NSBlockOperation *blocOpMain = [NSBlockOperation blockOperationWithBlock:^{
                //刷新UI
                NSLog(@"刷新UI");
            }];
            [[NSOperationQueue mainQueue]addOperation:blocOpMain];
            //移除观察者
            [self removeObserver:self forKeyPath:@"operationNum" context:nil];
        }
    }
}

@end

讲解

工程大概是这样的:
ViewController有一个属性operationNum是执行任务标记,我把它的值默认置为0,并且我把默认值设置放在KVO监听之前,并且监听的时候通过新值来判断,是因为我用KVO监听的时候判断的是0,如果等于0的话那一开始可能就已经会走一次了,所以我把设置operationNum放在KVO之前,到最后所有的任务都得到响应之后operationNum值就为0了,然后就会走监听方法。

@property(atomic,assign)NSInteger operationNum;
self.operationNum = 0;

[self addObserver:self forKeyPath:@"operationNum" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];

我在ViewController.m上创建了一个按钮,按钮一点击就会开始请求。每一个请求的开始的时候operationNum++;在响应代码调用的时候operationNum--,具体代码上面都有,这样输出来的效果如下:

Snip20170704_133.png

如果有任何疑问或者改进的地方,还请大家简书下评论,以上!

逗比.gif

相关文章

  • AFN多请求依赖(二)

    导读:AFN多请求依赖(一) AFN多请求依赖(一)中解决的是如何将不同的AFN请求有序的进行请求:即第一个请求发...

  • AFN多请求依赖(一)

    AFN之使用问题解析AFN多请求依赖(二) 一、基本简介 一直想要把自己这几年的相关的工作上遇到的知识点通过文字整...

  • iOS-网络相关

    本篇涵盖AFN、ASI、封装网络请求等. 1.iOS网络请求之ASI与AFN的二次封装及意义2.LXNetwork...

  • AFNetworking

    一、AFN的GET和POST请求 二、AFN的"下载+上传+响应体的几种解析方式+网络状态监听"

  • (转)iOS 网络请求汇总

    原生session的GET请求 原生session的POST请求 AFN的GET网络请求如下: AFN POS...

  • iOS AFN网络请求参数类型的变换(参数可用字符串)

    在正常使用AFN网络请求的时候,请求参数params基本都是一个字典类型,AFN会把字典处理成一个json格式的二...

  • iOS开发之AFNetworking框架

    AFN网络请求和文件上传下载 使用AFN框架处理网络数据请求,遇到以下报错: 首先AFN使用方法,都是从创建man...

  • 最简单的iOS网络请求

    做iOS开发,说到网络请求,大家可能都不约而同的提到AFN,可以说大家的网络请求都是用AFN封装而成,AFN的强大...

  • AFN请求

    // // ViewController.m // DOM解析 // // Created by on 2018/...

  • AFN请求

    Creating an Upload Task for a Multi-Part Request, with Pr...

网友评论

  • 张散愁:感谢,感谢
    KODIE:@张散愁 有作用就行,大家多抱着一份开源的心态,把大家遇到过的问题以及解决办法分享出来这样大家就能更高效的解决问题,我们有时候只知道查,反正别人会写,我们干嘛要花时间写?所以每个人都花时间写写,方便自己也方便他人...
    张散愁:@KODIE 我现在就遇到了这个问题,必须有顺序的请求接口,还要根据接口得到的数据做判断,是否请求别的接口。所有请求完了,还必须在同一个线程里更新realm 数据。所以必须感谢你
    KODIE:@张散愁 嗯?试过有帮助吗?有帮助的话我就收下你的谢意。:grin::grin::grin:

本文标题:AFN多请求依赖(二)

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