有时我们会遇到这样的需求:启动时需要从服务器获取一些配置信息,然后服务器其他接口的调用又依赖于这个接口返回的配置。
可以这样处理:
1、向服务器获取配置的接口,请求完成后发送通知,其他请求收到通知后可以执行了;
2、先调用获取请求配置的接口,其他接口放在它的回调中。这样又会有个问题,多个其他接口都调用这个接口,短时间内会重复请求服务器多次。
以下是一种解决办法,用数组把callback(在C中可以用函数指针实现)保存,同一时间,只进行一个请求,请求结束后,再把结果发给数组中的所有callback
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
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]; } } |
这个过程还可以添加其它标志位,比如有一次请求成功,后面的请求直接回调等;
也可以用在数据库等异步耗时的操作上