为什么NSURLSession不使用我配置的NSURLCache? [英] Why is NSURLSession don't use my configured NSURLCache?

查看:141
本文介绍了为什么NSURLSession不使用我配置的NSURLCache?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

iOS7带来 NSURLSession ,在 NSURLSessionConfigure 的帮助下,我们可以自定义URLCache,所以我尝试了,但是没有运气,似乎我的URLCache根本就没用过。

iOS7 brings NSURLSession, with the help of NSURLSessionConfigure, we can customize URLCache, so i tried it, but with no luck, it seems my URLCache is not used at all.

- (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,没有记录。

1) a test.urlcache folder is created under Caches folder, and with 3 files Cache.db, Cache.db-shm, Cache.db-wal, the size of Cache.db is 4KB, no records in it.

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

2) every time run the code, the first output of usage is always 0, after for loop ended, usage becomes 4096, the next time usage becomes 0 again.

推荐答案

似乎有两个潜在的问题:

Seems like there are two potential issues:


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

  1. Your cache is too small. Historically, it wouldn't cache if the item being cached exceeded 10% of the total cache size.

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

You're checking the disk usage 0.5 seconds after the last request. That might be too soon for the cache to be written to persistent storage.

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

Below I use a bigger cache and wait 10 seconds before final check of disk usage, and the cache works fine. I also use GCD to queue the serial tasks to eliminate the arbitrary 0.5 second delay, which is both safer, and makes it more obvious when it's retrieving data over network and when it's using the cache.

- (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 子类中。然后我可以使用依赖关系来指示最终的完成操作,但同时它们都允许并发,但也规定了并发度,但这似乎超出了原始问题的范围,我希望尽可能简单。

As an aside, for network tasks like this, I'd generally use operation queue rather than dispatch queue and then wrap my data tasks in concurrent NSOperation subclass. Then I can use dependencies to dictate the final completion operation, but at the same time both permit concurrency but also dictate the degree of concurrency, but this seemed outside the scope of the original question and I wanted to keep this as simple as possible.

这篇关于为什么NSURLSession不使用我配置的NSURLCache?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆