10

サーバーからのすべての http 応答には、応答をキャッシュしないようにアプリに通知するヘッダーが付属しています。

Cache-Control: no-cache
Pragma: no-cache
Expires: 0

そのため、デフォルトのキャッシュ ポリシー「NSURLRequestUseProtocolCachePolicy」で NSUrlRequests を作成している場合、アプリは常にサーバーからデータを読み込みます。ただし、応答をキャッシュする必要があり、明らかな解決策は、これらのヘッダーをたとえば (バックエンド側で) 10 秒に設定するなどの時間に設定することです。しかし、このポリシーをバイパスしてすべてのリクエストを 10 秒間キャッシュする方法に興味があります。

そのためには、共有キャッシュをセットアップする必要があります。これは、AppDelegate didFinishLaunchingWithOptions で行うことができます。

NSURLCache *URLCache = [[NSURLCache alloc] initWithMemoryCapacity:4 * 1024 * 1024
                                             diskCapacity:20 * 1024 * 1024
                                               diskPath:nil];
[NSURLCache setSharedURLCache:URLCache];

次に、応答を強制的にキャッシュするコードを埋め込む必要があります。AFHttpClient のインスタンスを使用する場合は、以下のメソッドをオーバーライドし、手動でキャッシュを共有キャッシュに格納することで実行できます。

- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
              willCacheResponse:(NSCachedURLResponse *)cachedResponse {

  NSMutableDictionary *mutableUserInfo = [[cachedResponse userInfo] mutableCopy];
  NSMutableData *mutableData = [[cachedResponse data] mutableCopy];
  NSURLCacheStoragePolicy storagePolicy = NSURLCacheStorageAllowedInMemoryOnly;

  // ...

  return [[NSCachedURLResponse alloc] initWithResponse:[cachedResponse response]
                                                data:mutableData
                                            userInfo:mutableUserInfo
                                       storagePolicy:storagePolicy];
}

最後に、リクエストの cachePolicy を設定します。この場合、すべてのリクエストに同じキャッシュ ポリシーを設定します。繰り返しますが、AFHttpClient のインスタンスを使用する場合は、以下のメソッドをオーバーライドすることで実行できます。

- (NSMutableURLRequest *)requestWithMethod:(NSString *)method path:(NSString *)path parameters:(NSDictionary *)parameters {

  NSMutableURLRequest *request = [super requestWithMethod:method path:path parameters:parameters];
  request.cachePolicy = NSURLRequestReturnCacheDataElseLoad;

  return request;
}

ここまでは順調ですね。「NSURLRequestReturnCacheDataElseLoad」は、最初にリクエストを実行し、それ以外の場合はキャッシュからレスポンスをロードします。問題は、キャッシュの有効期限 (たとえば 10 秒) を設定する方法が不明であることです。

4

3 に答える 3

11

誰かが興味を持っている場合は、Swift で書き直された Stephanus の回答を次に示します。

class CustomURLCache: NSURLCache {

    // UserInfo expires key
    let kUrlCacheExpiresKey = "CacheData";

    // How long is cache data valid in seconds
    let kCacheExpireInterval:NSTimeInterval = 60*60*24*5;

    // get cache response for a request
    override func cachedResponseForRequest(request:NSURLRequest) -> NSCachedURLResponse? {
        // create empty response
        var response:NSCachedURLResponse? = nil

        // try to get cache response
        if let cachedResponse = super.cachedResponseForRequest(request) {

            // try to get userInfo
            if let userInfo = cachedResponse.userInfo {

                // get cache date
                if let cacheDate = userInfo[kUrlCacheExpiresKey] as NSDate? {

                    // check if the cache data are expired
                    if (cacheDate.timeIntervalSinceNow < -kCacheExpireInterval) {
                        // remove old cache request
                        self.removeCachedResponseForRequest(request);
                    } else {
                        // the cache request is still valid
                        response = cachedResponse
                    }
                }
            }
        }

        return response;
    }

    // store cached response
    override func storeCachedResponse(cachedResponse: NSCachedURLResponse, forRequest: NSURLRequest) {
        // create userInfo dictionary
        var userInfo = NSMutableDictionary()
        if let cachedUserInfo = cachedResponse.userInfo {
            userInfo = NSMutableDictionary(dictionary:cachedUserInfo)
        }
        // add current date to the UserInfo
        userInfo[kUrlCacheExpiresKey] = NSDate()

        // create new cached response
        let newCachedResponse = NSCachedURLResponse(response:cachedResponse.response, data:cachedResponse.data, userInfo:userInfo,storagePolicy:cachedResponse.storagePolicy)
        super.storeCachedResponse(newCachedResponse, forRequest:forRequest)

    }

}
于 2014-10-17T15:18:28.410 に答える
11

有効期限が切れていないキャッシュされた応答のみを返すカスタム NSURLCache を実装できます。

例:

#import "CustomURLCache.h"

NSString * const EXPIRES_KEY = @"cache date";
int const CACHE_EXPIRES = -10;

@implementation CustomURLCache

// static method for activating this custom cache
+(void)activate {
    CustomURLCache *urlCache = [[CustomURLCache alloc] initWithMemoryCapacity:(2*1024*1024) diskCapacity:(2*1024*1024) diskPath:nil] ;
    [NSURLCache setSharedURLCache:urlCache];
}

-(NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request {
    NSCachedURLResponse * cachedResponse = [super cachedResponseForRequest:request];
    if (cachedResponse) {
        NSDate* cacheDate = [[cachedResponse userInfo] objectForKey:EXPIRES_KEY];
        if ([cacheDate timeIntervalSinceNow] < CACHE_EXPIRES) {
            [self removeCachedResponseForRequest:request];
            cachedResponse = nil;
        }
    }

    return cachedResponse;
}

- (void)storeCachedResponse:(NSCachedURLResponse *)cachedResponse forRequest:(NSURLRequest *)request {
    NSMutableDictionary *userInfo = cachedResponse.userInfo ? [cachedResponse.userInfo mutableCopy] : [NSMutableDictionary dictionary];
    [userInfo setObject:[NSDate date] forKey:EXPIRES_KEY];
    NSCachedURLResponse *newCachedResponse = [[NSCachedURLResponse alloc] initWithResponse:cachedResponse.response data:cachedResponse.data userInfo:userInfo storagePolicy:cachedResponse.storagePolicy];

    [super storeCachedResponse:newCachedResponse forRequest:request];
}

@end

これで十分な制御ができない場合は、以下のようにstartLoadingメソッドを使用してカスタム NSURLProtocol を実装し、それをカスタム キャッシュと組み合わせて使用​​します。

- (void)startLoading
{
    NSMutableURLRequest *newRequest = [self.request mutableCopy];
    [NSURLProtocol setProperty:@YES forKey:@"CacheSet" inRequest:newRequest];

    NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:self.request];
    if (cachedResponse) {  
        [self connection:nil didReceiveResponse:[cachedResponse response]];
        [self connection:nil didReceiveData:[cachedResponse data]];
        [self connectionDidFinishLoading:nil];
    } else {
        _connection = [NSURLConnection connectionWithRequest:newRequest delegate:self];
    }
}

いくつかのリンク:

于 2013-11-07T22:16:39.590 に答える
1

別の可能な解決策は、応答オブジェクトを変更し、サーバーから Cache-Control ヘッダーを削除して、それらを独自の目的の値に置き換えることです。

あなたがそれを行うことができる2つの場所があります。

NSURLSessionDataDelegateinで行うこともできfunc URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, willCacheResponse proposedResponse: NSCachedURLResponse, completionHandler: (NSCachedURLResponse?) -> Void)ますが、そこで行うと、セッション タスクから結果を取得する通常の完了ハンドラ ベースのメソッドを使用できなくなります。

NSURLProtocol別の方法として、HTTP および HTTPS 応答をインターセプトして変更するcustom を定義することもできます。

于 2015-09-22T21:28:48.033 に答える