AFN多請求依賴(二)

導讀:AFN多請求依賴(一)

AFN多請求依賴(一)中解決的是如何將不同的AFN請求有序的進行請求:即第一個請求發(fā)出并且得到響應之后再次發(fā)出下一個請求并且得到響應,以此類推,最終在最后的一個請求得到響應之后執(zhí)行刷新UI等操作。那么一中用到的技術主要是信號量。

但是有一個問題這樣的異步AFN請求就相當于同步了,挨個挨個和主線程的同步沒什么區(qū)別,耗費時間比較長,那么我們現(xiàn)在有一個需求就是當所有的請求發(fā)出之后,只要響應都接收到了那么就刷新UI,不需要排隊挨個挨個去請求,但是一定要等到所有的請求請求到結果之后再刷新UI等操作,那么這個用到信號量肯定是不合適的,那么該怎么弄呢?

大家可以試一下其他的方式,比如說GCD的組之類的,但是我試過了不行,可能是我加的方式不對,大家有更好的方式還請簡書留言,本文中使用的是使用一個Flag來標志,每次發(fā)送請求的時候Flag值+1;得到響應之后Flag值建-1;當用KVO監(jiān)聽到值為0時,刷新UI等操作,并且移除監(jiān)聽。

工具準備

  • 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
{
    //創(chuàng)建請求管理者
    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發(fā)送請求
    [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);
    }];
}

//監(jiān)聽
-(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(@"任務執(zhí)行完畢");
            NSBlockOperation *blocOpMain = [NSBlockOperation blockOperationWithBlock:^{
                //刷新UI
                NSLog(@"刷新UI");
            }];
            [[NSOperationQueue mainQueue]addOperation:blocOpMain];
            //移除觀察者
            [self removeObserver:self forKeyPath:@"operationNum" context:nil];
        }
    }
}

@end

講解

工程大概是這樣的:
ViewController有一個屬性operationNum是執(zhí)行任務標記,我把它的值默認置為0,并且我把默認值設置放在KVO監(jiān)聽之前,并且監(jiān)聽的時候通過新值來判斷,是因為我用KVO監(jiān)聽的時候判斷的是0,如果等于0的話那一開始可能就已經會走一次了,所以我把設置operationNum放在KVO之前,到最后所有的任務都得到響應之后operationNum值就為0了,然后就會走監(jiān)聽方法。

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

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

我在ViewController.m上創(chuàng)建了一個按鈕,按鈕一點擊就會開始請求。每一個請求的開始的時候operationNum++;在響應代碼調用的時候operationNum--,具體代碼上面都有,這樣輸出來的效果如下:

Snip20170704_133.png

如果有任何疑問或者改進的地方,還請大家簡書下評論,以上!

逗比.gif
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • *面試心聲:其實這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個offer,總結起來就是把...
    Dove_iOS閱讀 27,217評論 30 472
  • 發(fā)現(xiàn) 關注 消息 iOS 第三方庫、插件、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,252評論 4 61
  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,991評論 19 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,524評論 25 708
  • 讀書分享 D10 第九章(110-117)曲金鳳 摘抄: 1, 理性(或說理智)會讓人發(fā)瘋、混亂、糊涂: 無端地追...
    輕風style閱讀 817評論 -1 3