为什么NSURLSession不使用我配置的NSURLCache?

 煙獨享寂寞 发布于 2023-02-08 11:39

iOS7带来NSURLSessionNSURLSessionConfigure,我们可以自定义URLCache,所以我尝试了,但没有运气,似乎我的URLCache根本没用过.

- (void)testURLCache
{
    NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
    config.requestCachePolicy = NSURLRequestUseProtocolCachePolicy;
    NSURLCache *cache = [[NSURLCache alloc] initWithMemoryCapacity:1024 * 100 diskCapacity:1024 * 100 diskPath:@"test.urlcache"];

    NSLog(@"usage:%lu", (unsigned long)[cache currentDiskUsage]);

    config.URLCache = cache;

    NSURLSession *session = [NSURLSession sessionWithConfiguration:config];
    for (int i = 0; i < 40; i++) {
        NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://ajax.googleapis.com/ajax/libs/angularjs/1.2.6/angular.min.js?%d", i]]];
        NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
            if (error) {
                NSLog(@"error:%@", error);
            } else {
                NSLog(@"done:%d", i);
            }
        }];
        [task resume];
        [NSThread sleepForTimeInterval:0.5];
    }
    NSLog(@"usage:%lu", (unsigned long)[cache currentDiskUsage]);
}

我观察到的东西:

1)一个test.urlcache文件夹下创建Caches文件夹,并用3个文件Cache.db,Cache.db-shm,Cache.db-wal,的大小Cache.db是4KB,在它没有记录.

2)每次运行代码时,第一次使用输出始终为0,在循环结束后,使用量变为4096,下次使用次数再次变为0.

1 个回答
  • 似乎有两个潜在的问题:

      你的缓存太小了.从历史上看,如果缓存的项超过总缓存大小的10%,则不会缓存.

      您在最后一次请求后0.5秒检查磁盘使用情况.将缓存写入持久存储可能为时尚早.

    下面我使用更大的缓存并在最终检查磁盘使用情况之前等待10秒,缓存工作正常.我还使用GCD对串行任务进行排队,以消除任意0.5秒延迟,这更加安全,并且当它通过网络检索数据以及何时使用缓存时更加明显.

    - (void)testURLCache
    {
        NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
        config.requestCachePolicy = NSURLRequestUseProtocolCachePolicy;
    
        // this is too small and won't cache
        // NSURLCache *cache = [[NSURLCache alloc] initWithMemoryCapacity:100 * 1024 diskCapacity:100 * 1024 diskPath:@"small.urlcache"];
    
        // use bigger cache
        NSURLCache *cache = [[NSURLCache alloc] initWithMemoryCapacity:10 * 1024 * 1024 diskCapacity:20 * 1024 * 1024 diskPath:@"big.urlcache"];
    
        config.URLCache = cache;
    
        // I'm going to add tasks to serial queue so that (a) I don't block main queue;
        // and (b) I don't need arbitrary delay, but I can just signal when it's done.
    
        dispatch_queue_t queue = dispatch_queue_create("com.domain.app.datatasks", 0);
    
        NSURLSession *session = [NSURLSession sessionWithConfiguration:config];
        for (int i = 0; i < 40; i++) {
            dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    
            dispatch_async(queue, ^{
                NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://ajax.googleapis.com/ajax/libs/angularjs/1.2.6/angular.min.js?%d", i]]];
                NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    
                    if (error) {
                        NSLog(@"error:%@", error);
                    } else {
                        NSLog(@"done:%d", i);
                    }
    
                    dispatch_semaphore_signal(semaphore);                   // signal dispatched block that request is done
                }];
                [task resume];
    
                dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);  // wait until task is complete
            });
        }
    
        // when the queued tasks finish, then check disk usage both immediately and 10 seconds later
    
        dispatch_async(queue, ^{
    
            // check cache size immediately after the data tasks finish
    
            NSLog(@"usage:%lu", (unsigned long)[cache currentDiskUsage]);
    
            // check again in 10 seconds
    
            double delayInSeconds = 10.0;
            dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
            dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
                NSLog(@"usage:%lu", (unsigned long)[cache currentDiskUsage]);
            });
        });
    }
    

    顺便说一句,对于像这样的网络任务,我通常使用操作队列而不是调度队列,然后将我的数据任务包装在并发NSOperation子类中.然后我可以使用依赖关系来指示最终的完成操作,但同时它们都允许并发,但也决定了并发度,但这似乎超出了原始问题的范围,我希望尽可能简单.

    2023-02-08 11:42 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有