一 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不会提前结束,依赖关系有效。