AFN多请求依赖(二)

导读: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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,588评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,456评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,146评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,387评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,481评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,510评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,522评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,296评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,745评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,039评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,202评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,901评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,538评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,165评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,415评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,081评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,085评论 2 352

推荐阅读更多精彩内容

  • *面试心声:其实这些题本人都没怎么背,但是在上海 两周半 面了大约10家 收到差不多3个offer,总结起来就是把...
    Dove_iOS阅读 27,139评论 30 470
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,081评论 4 62
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,646评论 18 139
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,973评论 25 707
  • 读书分享 D10 第九章(110-117)曲金凤 摘抄: 1, 理性(或说理智)会让人发疯、混乱、糊涂: 无端地追...
    轻风style阅读 785评论 -1 3