簡體   English   中英

如何使用NSURLSession和NSURLCache進行緩存。 不工作

[英]How to cache using NSURLSession and NSURLCache. Not working

我有一個測試應用程序設置,即使用戶在下載過程中切換應用程序,它也能成功從網絡下載內容。 太好了,現在我有后台下載了。 現在我想添加緩存。 沒有必要讓我多次下載圖像,b / c系統設計,給定一個圖像URL我可以告訴你該URL后面的內容永遠不會改變。 所以,現在我想使用Apple內置的內存/磁盤緩存來緩存下載的結果,我已經閱讀了很多(而不是我在NSCachesDirectory中手動保存文件,然后在創建之前檢查文件)請求,ick)。 試圖獲取緩存在此工作的代碼頂部的工作,我添加以下代碼:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Override point for customization after application launch.

    // Set app-wide shared cache (first number is megabyte value)
    [NSURLCache setSharedURLCache:[[NSURLCache alloc] initWithMemoryCapacity:60 * 1024 * 1024
                                                                diskCapacity:200 * 1024 * 1024
                                                                    diskPath:nil]];

    return YES;
}

當我創建會話時,我添加了兩行NEW(URLCache和requestCachePolicy)。

// Helper method to get a single session object
- (NSURLSession *)backgroundSession
{
    static NSURLSession *session = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfiguration:@"com.example.apple-samplecode.SimpleBackgroundTransfer.BackgroundSession"];
        configuration.URLCache = [NSURLCache sharedURLCache]; // NEW LINE ON TOP OF OTHERWISE WORKING CODE
        configuration.requestCachePolicy = NSURLRequestReturnCacheDataElseLoad;  // NEW LINE ON TOP OF OTHERWISE WORKING CODE
        session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];
    });
    return session;
}

然后,為了看到緩存成功,我只是為了超冗余而切換了我的NSURLRequest線

// NSURLRequest *request = [NSURLRequest requestWithURL:downloadURL]; // Old line, I've replaced this with...
NSURLRequest *request = [NSURLRequest requestWithURL:downloadURL cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:2*60]; // New line

現在,當我第二次下載該項目時,體驗就像第一次一樣! 需要很長時間才能下載和進度條動畫緩慢而穩定,就像原始下載一樣。 我想立即在緩存中的數據!! 我錯過了什么?

---------------------------- UPDATE --------------------- -------

好的,感謝Thorsten的回答,我在didFinishDownloadingToURL委托方法中添加了以下兩行代碼:

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)downloadURL {

    // Added these lines...
    NSLog(@"DiskCache: %@ of %@", @([[NSURLCache sharedURLCache] currentDiskUsage]), @([[NSURLCache sharedURLCache] diskCapacity]));
    NSLog(@"MemoryCache: %@ of %@", @([[NSURLCache sharedURLCache] currentMemoryUsage]), @([[NSURLCache sharedURLCache] memoryCapacity]));
    /*
    OUTPUTS:
    DiskCache: 4096 of 209715200
    MemoryCache: 0 of 62914560
    */
}

這很棒。 它證實緩存正在增長。 我認為,因為我使用的是downloadTask(下載到文件而不是內存),這就是為什么DiskCache正在增長而不是內存緩存? 我想一切都會進入內存緩存,直到溢出,然后將使用磁盤緩存,並且可能在操作系統在后台殺死應用程序以釋放內存之前,內存緩存已寫入磁盤。 我誤解了Apple的緩存是如何工作的嗎?

這是向前邁出的一步,但第二次下載文件時, 它只需要第一次 (可能是10秒左右)並且以下方法再次執行:

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
    // This shouldn't execute the second time around should it? Even if this is supposed to get executed a second time around then shouldn't it be lightning fast? It's not.
    // On all subsequent requests, it slowly iterates through the downloading of the content just as slow as the first time. No caching is apparent. What am I missing?
}

你對我上面的編輯有什么看法? 為什么我在后續請求中沒有看到文件很快返回?

如何在第二個請求中確認文件是否從緩存中提供?

請注意,以下SO帖子幫助我解決了我的問題: NSURLCache是​​否在發布期間持續存在?

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Set app-wide shared cache (first number is megabyte value)
    NSUInteger cacheSizeMemory = 500*1024*1024; // 500 MB
    NSUInteger cacheSizeDisk = 500*1024*1024; // 500 MB
    NSURLCache *sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:cacheSizeMemory diskCapacity:cacheSizeDisk diskPath:@"nsurlcache"];
    [NSURLCache setSharedURLCache:sharedCache];
    sleep(1); // Critically important line, sadly, but it's worth it!
}

除了sleep(1)行之外,還要注意我的緩存大小; 500MB。

根據文檔,您需要一個比您嘗試緩存的緩存大小更大的緩存大小。

響應大小足夠小,可以合理地適應緩存。 (例如,如果提供磁盤緩存,則響應不得大於磁盤緩存大小的約5%。)

因此,例如,如果您希望能夠緩存10MB圖像,那么10MB甚至20MB的緩存大小是不夠的。 你需要200MB。 下面是Honey的評論,證明Apple正遵循這一5%的規則。 對於8Mb,他必須將緩存大小設置為最小154MB。

解決方案 - 首先獲取所有信息,你需要這樣的東西

- (void)loadData
{
    if (!self.commonDataSource) {
        self.commonDataSource = [[NSArray alloc] init];
    }

    [self setSharedCacheForImages];

    NSURLSession *session = [self prepareSessionForRequest];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[BaseURLString stringByAppendingPathComponent:@"app.json"]]];
    [request setHTTPMethod:@"GET"];
    __weak typeof(self) weakSelf = self;
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (!error) {
            NSArray *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
            weakSelf.commonDataSource = jsonResponse;
            dispatch_async(dispatch_get_main_queue(), ^{
                [weakSelf updateDataSource];
            });
        }
    }];
    [dataTask resume];
}

- (void)setSharedCacheForImages
{
    NSUInteger cashSize = 250 * 1024 * 1024;
    NSUInteger cashDiskSize = 250 * 1024 * 1024;
    NSURLCache *imageCache = [[NSURLCache alloc] initWithMemoryCapacity:cashSize diskCapacity:cashDiskSize diskPath:@"someCachePath"];
    [NSURLCache setSharedURLCache:imageCache];
}

- (NSURLSession *)prepareSessionForRequest
{
    NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
    [sessionConfiguration setHTTPAdditionalHeaders:@{@"Content-Type": @"application/json", @"Accept": @"application/json"}];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration];
    return session;
}

在您需要下載每個文件后 - 在我的情況下 - 進行響應解析和下載圖像。 在提出請求之前,您還需要檢查緩存是否已經響應了您的請求 - 就像這樣

NSString *imageURL = [NSString stringWithFormat:@"%@%@", BaseURLString ,sourceDictionary[@"thumb_path"]];
NSURLSession *session = [self prepareSessionForRequest];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:imageURL]];
[request setHTTPMethod:@"GET"];

NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request];
if (cachedResponse.data) {
    UIImage *downloadedImage = [UIImage imageWithData:cachedResponse.data];
    dispatch_async(dispatch_get_main_queue(), ^{
        cell.thumbnailImageView.image = downloadedImage;
    });
} else {
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    if (!error) {
        UIImage *downloadedImage = [UIImage imageWithData:data];
        dispatch_async(dispatch_get_main_queue(), ^{
            cell.thumbnailImageView.image = downloadedImage;
        });
    }
}];
    [dataTask resume];
}

之后,您還可以使用xCode Network Analyzer檢查結果。

另請注意由@jcaron提及並由Apple記錄

NSURLSession不會嘗試緩存大於緩存大小5%的文件

結果像

在此輸入圖像描述

設置緩存和會話后,應使用會話方法下載數據:

- (IBAction)btnClicked:(id)sender {
    NSString *imageUrl = @"http://placekitten.com/1000/1000";
    NSURLSessionDataTask* loadDataTask = [session dataTaskWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:imageUrl]] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        UIImage *downloadedImage = [UIImage imageWithData:data];
        NSLog(@"ImageSize: %f, %f", downloadedImage.size.width, downloadedImage.size.height);
        NSLog(@"DiskCache: %i of %i", [[NSURLCache sharedURLCache] currentDiskUsage], [[NSURLCache sharedURLCache] diskCapacity]);
        NSLog(@"MemoryCache: %i of %i", [[NSURLCache sharedURLCache] currentMemoryUsage], [[NSURLCache sharedURLCache] memoryCapacity]);
    }];
    [loadDataTask resume]; //start request
}

第一次調用后,圖像被緩存。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM