我有两个使用AFNetworking发起的网络请求,分别是接口A和接口B。要求是:必须等接口A的请求完成后,才开始请求接口B,但是我不希望把接口B的请求代码直接写在接口A的回调(completi...

一 GCD串行队列结合信号量实现:

dispatch_queue_t serialQueue = dispatch_queue_create("com.example.network", DISPATCH_QUEUE_SERIAL);

//这里必须创建一个非主线秤队列,不然会卡死

dispatch_async(serialQueue, ^{

    dispatch_semaphore_t sema = dispatch_semaphore_create(0);

    [managerA GET:@"接口A" parameters:nil headers:nil progress:nil success:^(NSURLSessionDataTask *task, id responseObject) {

        // A请求完成

        dispatch_semaphore_signal(sema);

    } failure:^(NSURLSessionDataTask *task, NSError *error) {

        dispatch_semaphore_signal(sema);

    }];

    dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);

});

dispatch_async(serialQueue, ^{

    [managerB GET:@"接口B" parameters:nil headers:nil progress:nil success:^(NSURLSessionDataTask *task, id responseObject) {

        // B请求完成

    } failure:^(NSURLSessionDataTask *task, NSError *error) {

        // B请求失败

    }];

});

方法二:NSOperationQueue依赖

AFNRequestOperation *opA = [[AFNRequestOperation alloc] initWithManager:managerA url:@"接口A" parameters:nil];

AFNRequestOperation *opB = [[AFNRequestOperation alloc] initWithManager:managerB url:@"接口B" parameters:nil];

[opB addDependency:opA];

NSOperationQueue *queue = [[NSOperationQueue alloc] init];

[queue addOperations:@[opA, opB] waitUntilFinished:NO];

AFNRequestOperation 封装

#import <Foundation/Foundation.h>

#import <AFNetworking/AFNetworking.h>

typedef void(^AFNRequestCompletion)(id responseObject, NSError *error);

@interface AFNRequestOperation : NSOperation

- (instancetype)initWithManager:(AFHTTPSessionManager *)manager

                            url:(NSString *)url

                    parameters:(NSDictionary *)parameters

                    completion:(AFNRequestCompletion)completion;

@end

#import "AFNRequestOperation.h"

@interface AFNRequestOperation ()

@property (nonatomic, strong) AFHTTPSessionManager *manager;

@property (nonatomic, copy) NSString *url;

@property (nonatomic, strong) NSDictionary *parameters;

@property (nonatomic, copy) AFNRequestCompletion completion;

@property (nonatomic, assign) BOOL finishedFlag;

@property (nonatomic, assign) BOOL executingFlag;

@end

@implementation AFNRequestOperation

- (instancetype)initWithManager:(AFHTTPSessionManager *)manager

                            url:(NSString *)url

                    parameters:(NSDictionary *)parameters

                    completion:(AFNRequestCompletion)completion {

    if (self = [super init]) {

        self.manager = manager;

        self.url = url;

        self.parameters = parameters;

        self.completion = completion;

    }

    return self;

}

- (void)start {

    if (self.isCancelled) {

        [self finish];

        return;

    }

    [self willChangeValueForKey:@"isExecuting"];

    self.executingFlag = YES;

    [self didChangeValueForKey:@"isExecuting"];


    [self.manager GET:self.url parameters:self.parameters headers:nil progress:nil success:^(NSURLSessionDataTask *task, id responseObject) {

        if (self.completion) self.completion(responseObject, nil);

        [self finish];

    } failure:^(NSURLSessionDataTask *task, NSError *error) {

        if (self.completion) self.completion(nil, error);

        [self finish];

    }];

}

- (void)finish {

    [self willChangeValueForKey:@"isExecuting"];

    [self willChangeValueForKey:@"isFinished"];

    self.executingFlag = NO;

    self.finishedFlag = YES;

    [self didChangeValueForKey:@"isExecuting"];

    [self didChangeValueForKey:@"isFinished"];

}

- (BOOL)isAsynchronous { return YES; }

- (BOOL)isExecuting { return self.executingFlag; }

- (BOOL)isFinished { return self.finishedFlag; }

@end

用法示例

AFNRequestOperation *opA = [[AFNRequestOperation alloc] initWithManager:managerA url:@"接口A" parameters:nil completion:^(id response, NSError *error) {

    NSLog(@"A完成");

}];

AFNRequestOperation *opB = [[AFNRequestOperation alloc] initWithManager:managerB url:@"接口B" parameters:nil completion:^(id response, NSError *error) {

    NSLog(@"B完成");

}];

[opB addDependency:opA];

NSOperationQueue *queue = [[NSOperationQueue alloc] init];

[queue addOperations:@[opA, opB] waitUntilFinished:NO];

NSOperationQueue 会根据依赖关系([opB addDependency:opA])自动管理任务的执行顺序。

只有当 opA 执行完毕(即A的请求完成并且finish被调用,isFinished变为YES),opB 才会开始执行。

你不需要在A的回调里手动触发B,队列会自动帮你管理。

由于AFN的网络请求是异步的,而NSOperation的main或block是同步的,如果你直接在main里发起异步请求,main方法会立刻返回,导致NSOperation提前结束,依赖关系就失效了。

所以,需要用信号量让NSOperation等待AFN异步请求完成后再结束。

其实我前面给你的AFNRequestOperation实现里已经用到了类似的机制(通过finish方法和KVO),但你也可以用信号量来实现。

结合信号量的NSOperation示例

@interface AFNRequestOperation : NSOperation

@property (nonatomic, strong) AFHTTPSessionManager *manager;

@property (nonatomic, copy) NSString *url;

@property (nonatomic, strong) NSDictionary *parameters;

@property (nonatomic, copy) void (^completion)(id response, NSError *error);

@end

@implementation AFNRequestOperation

- (void)main {

    if (self.isCancelled) return;

    dispatch_semaphore_t sema = dispatch_semaphore_create(0);

    [self.manager GET:self.url parameters:self.parameters headers:nil progress:nil success:^(NSURLSessionDataTask *task, id responseObject) {

        if (self.completion) self.completion(responseObject, nil);

        dispatch_semaphore_signal(sema);

    } failure:^(NSURLSessionDataTask *task, NSError *error) {

        if (self.completion) self.completion(nil, error);

        dispatch_semaphore_signal(sema);

    }];

    // 等待网络请求完成

    dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);

}

@end

用法

AFNRequestOperation *opA = [AFNRequestOperation new];

opA.manager = managerA;

opA.url = @"接口A";

opA.completion = ^(id response, NSError *error) {

    NSLog(@"A完成");

};

AFNRequestOperation *opB = [AFNRequestOperation new];

opB.manager = managerB;

opB.url = @"接口B";

opB.completion = ^(id response, NSError *error) {

    NSLog(@"B完成");

};

[opB addDependency:opA];

NSOperationQueue *queue = [NSOperationQueue new];

[queue addOperations:@[opA, opB] waitUntilFinished:NO];

这样写,A和B的请求会严格按照依赖顺序执行,且不会写在回调里。

信号量保证了NSOperation不会提前结束,依赖关系有效。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容