iOS多个线程请求同一API的资源,避免重复请求

有时我们会遇到这样的需求:启动时需要从服务器获取一些配置信息,然后服务器其他接口的调用又依赖于这个接口返回的配置。

可以这样处理:

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];
    }
}

这个过程还可以添加其它标志位,比如有一次请求成功,后面的请求直接回调等;

也可以用在数据库等异步耗时的操作上

如果文章对你有帮助,欢迎点赞或打赏(金额不限)。你的打赏将全部用于支付网站服务器费用和提高网站文章质量,谢谢支持。

版权声明:

本文由 原创,商业转载请联系作者获得授权。
非商业转载请注明作者 雅乐网 ,并附带本文链接:
https://www.yalewoo.com/ios_multiple-threads-request-resources-from-the-same-api-to-avoid-duplicate-requests.html

上一篇:

下一篇:

我要评论

验证码*: 0 + 9 =