有时我们会遇到这样的需求:启动时需要从服务器获取一些配置信息,然后服务器其他接口的调用又依赖于这个接口返回的配置。
可以这样处理:
1、向服务器获取配置的接口,请求完成后发送通知,其他请求收到通知后可以执行了;
2、先调用获取请求配置的接口,其他接口放在它的回调中。这样又会有个问题,多个其他接口都调用这个接口,短时间内会重复请求服务器多次。
以下是一种解决办法,用数组把callback(在C中可以用函数指针实现)保存,同一时间,只进行一个请求,请求结束后,再把结果发给数组中的所有callback
typedef void(^MYServerConfigLoadBlock)(NSData *data);
+ (void)loadServerConfigurationWithCompletionBlock:(MYServerConfigLoadBlock)completionBlock
{
NSString *urlStr = @"http://www.baidu.com";
@synchronized (self) { //加锁,避免数组重复创建添加等问题
static NSMutableArray *_completionBlocks; //用数组保存回调
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_completionBlocks = [NSMutableArray array]; //仅创建一次数组
});
if (completionBlock) { //每调用一次此函数,就把回调加进数组中
[_completionBlocks addObject:[completionBlock copy]];
}
static BOOL isProcessing = NO; //如果已经在请求了,就不再发出新的请求
if (isProcessing == YES) {
return;
}
isProcessing = YES;
NSURL *URL = [NSURL URLWithString:urlStr];
NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithURL:URL completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
@synchronized (self) { //网络请求的回调也要加锁,这里是另一个线程了
for (MYServerConfigLoadBlock block in _completionBlocks) { //遍历回调数组,把结果发给每个调用者
block(data);
}
[_completionBlocks removeAllObjects];
isProcessing = NO;
}
}];
[task resume];
}
}
这个过程还可以添加其它标志位,比如有一次请求成功,后面的请求直接回调等;
也可以用在数据库等异步耗时的操作上
支付宝打赏
微信打赏