2012-04-20 4 views
36

すべてのネットワーク操作にAFNetworkingSDURLCacheを使用しています。AFNetworkingとオフラインモードが動作しないSDURLCache

私が持っているこのようなSDURLCacheセット:

SDURLCache *urlCache = [[SDURLCache alloc] 
     initWithMemoryCapacity:1024*1024*2 // 2MB mem cache 
     diskCapacity:1024*1024*15 // 15MB disk cache 
     diskPath:[SDURLCache defaultCachePath]]; 
    [urlCache setMinCacheInterval:1]; 
    [NSURLCache setSharedURLCache:urlCache]; 

すべての私の要求は、りんごのドキュメントによると、このように動作しますのCachePolicy NSURLRequestUseProtocolCachePolicyを、使用している:

NSCachedURLResponseが要求のために存在しない場合、元のソースから データがフェッチされます。要求に応じてキャッシュされた 応答がある場合、URLローディングシステムは応答 をチェックして、コンテンツの再検証が必要であると指定しているかどうかを判断します。 コンテンツの再検証が必要な場合は、 発信元に接続が変更されているかどうかが確認されます。変更されていない場合は、 の応答がローカルキャッシュから返されます。変更されている場合は、 元のソースからデータがフェッチされます。

キャッシュされた応答でコンテンツの再検証が必要であると指定されていない場合は、応答 で指定された最大有効期間または有効期限が検査されます。キャッシュされた応答が十分に最新である場合、 応答がローカル・キャッシュから戻されます。応答が無効であると判定された場合は、 のデータが新しいかどうかを確認します( )。より新しいデータが利用可能であれば、データは 発信元からフェッチされ、それ以外の場合はキャッシュから返されます。

飛行機モードであっても、キャッシュが古くない限り、すべてが完全に機能します。キャッシュが期限切れになると(max-ageなど)、障害ブロックが呼び出されます。

だからこれで(私は文字列にデータを解析されてきたし、それがキャッシュされた情報が含まれています)

- (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request { 
    request = [SDURLCache canonicalRequestForRequest:request]; 

    NSCachedURLResponse *memoryResponse = 
     [super cachedResponseForRequest:request]; 
    if (memoryResponse) { 
     return memoryResponse; 
    } 

    NSString *cacheKey = [SDURLCache cacheKeyForURL:request.URL]; 

    // NOTE: We don't handle expiration here as even staled cache data is 
    // necessary for NSURLConnection to handle cache revalidation. 
    // Staled cache data is also needed for cachePolicies which force the 
    // use of the cache. 
    __block NSCachedURLResponse *response = nil; 
    dispatch_sync(get_disk_cache_queue(), ^{ 
     NSMutableDictionary *accesses = [self.diskCacheInfo 
      objectForKey:kAFURLCacheInfoAccessesKey]; 
     // OPTI: Check for cache-hit in in-memory dictionary before to hit FS 
     if ([accesses objectForKey:cacheKey]) { 
      response = [NSKeyedUnarchiver unarchiveObjectWithFile: 
       [_diskCachePath stringByAppendingPathComponent:cacheKey]]; 
      if (response) { 
       // OPTI: Log entry last access time for LRU cache eviction 
       // algorithm but don't save the dictionary 
       // on disk now in order to save IO and time 
       [accesses setObject:[NSDate date] forKey:cacheKey]; 
       _diskCacheInfoDirty = YES; 
      } 
     } 
    }); 

    // OPTI: Store the response to memory cache for potential future requests 
    if (response) { 
     [super storeCachedResponse:response forRequest:request]; 
    } 

    return response; 
} 

を私はSDURLCache内で少し掘ってきたし、この方法が有効なデータで応答を返す

私は応答がOSによって処理され、その後AFNetworkingAFURLConnectionOperation内部

- (void)connection:(NSURLConnection *)__unused connection 
    didFailWithError:(NSError *)error 

を受けると考えているため、ポイントは、私は、何をすべきか見当がつかない。

+0

私は現在まったく同じ問題に直面しています。あなたは解決策を見つけましたか? – mkto

+0

いいえ、私は畏敬の念を抱くような回避策を講じました.--( – Ecarrion

+0

SDURLCacheをフォークしたピートにメールを送りました。うまくいけば彼に答えがあります。 – mkto

答えて

10

は、まあ、私は最終的にないので、醜い回避策に到達しました:

まず

あなたはIOS5/IOS6を使用しているあなたはSDURLCacheをドロップして使用できる場合ネイティブ1:

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

しかし、IOS5ではhttps要求がIOS6でキャッシュされないことに注意してください。私達は私達のPrefix.pchに次のフレームワークを追加する必要が

セカンド

のでAFNetworkingは、当社のインターネット接続の監視を開始することができます。

#import <MobileCoreServices/MobileCoreServices.h> 
#import <SystemConfiguration/SystemConfiguration.h> 

第三に私たちが必要とAFHTTPClientインスタンスが私たちは私たちが今検出することができ、すべての発信要求をインターセプトし、コードのこれらの個展に出せると彼のcachePolicy

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

    NSMutableURLRequest * request = [super requestWithMethod:method path:path parameters:parameters]; 
    if (request.cachePolicy == NSURLRequestUseProtocolCachePolicy && self.networkReachabilityStatus == AFNetworkReachabilityStatusNotReachable) { 
     request.cachePolicy = NSURLRequestReturnCacheDataDontLoad; 
    } 

    if (self.networkReachabilityStatus == AFNetworkReachabilityStatusUnknown) { 

     puts("uknown reachability status"); 
    } 

    return request; 
} 

を変更することができます

たときに無線LAN/3gは利用できず、何にかかわらず常にキャッシュを使用する要求を指定します。 (オフラインモード)

ノート

  • networkReachabilityStatusこれは、要求がアプリケーションが起動するとすぐに行われている起こることができAFNetworkReachabilityStatusUnknownで、AFがいないとき、私はまだ何をするか分かりませんまだインターネットの状態を取得しました。

  • これが機能するには、サーバーがhttp応答に正しいキャッシュヘッダーを設定する必要があることに注意してください。

がIOS6のように見えるUPDATEがno-インターネットの状況にキャッシュされた応答をロードするいくつかの問題を持っているので、要求がキャッシュされ、要求キャッシュポリシーがNSURLRequestReturnCacheDataDontLoadにsetedされている場合でも、要求は失敗します。

AFURLConnectionOperation.m(void)connection:(NSURLConnection __unused *)connection didFailWithError:(NSError *)errorを変更して、要求が失敗した場合にキャッシュされた応答を取得し、特定のキャッシュポリシーに対してのみキャッシュされた応答を取得するのが醜い回避策です。

+1

本当に有益な要約、この答えに感謝します。最後のコード例のいくつかの部分を変更する必要があると思います。あなたの追加は '[self finished]'を呼び出す前に適用しなければなりません。そうでなければ 'failure'ブロックが呼び出されるかもしれません。私は本当にこれをデバッグするのを難しくした競合状態も経験しました。 –

+1

また、私は最終的にSDURLCacheを使用して終わったと言わなければなりません。 NSURLCacheはオフラインモードでiOS 6でキャッシュされた応答を確実に返しませんでした。何が痛い。 –

+2

オクラホマ、私はアップルから直接これに関するニュースを受け取りました。私はiOS Tech Talkでアップルのエンジニアと話していました。 * Me:* "NSURLCacheを使用してディスクキャッシュをサポートするようになりました...." * Appleの人:* "いいえ、そうではありません!"その後、明示的なオフラインシナリオ用に作成されたものではなく、Safariを高速化するように設計されているため、手動ダウンロードには使用しないでください。 - なぜ彼らはドキュメントでそれを書いていませんでしたか?生涯数時間で私を救ったでしょうか。 –

0

あなたのHTTPヘッダーなしではほとんど分かりませんが、最も一般的な理由はNSURLProtocol WebViewにキャッシュされた応答を配信する前に再検証を強制することです。

ここで見てみてください:あなたは、要求が成功したいよう http://robnapier.net/blog/offline-uiwebview-nsurlprotocol-588

+0

多くの警告(著者による)の多くの良いヒント – JOM

0

それは、キャッシュはデータの有効期限が切れていると、サーバから取得する必要があると言うにもかかわらず、聞こえます。特定の要求ののキャッシュポリシー(オンラインとオフラインの異なるポリシー)を設定する運があるかもしれません。

NSMutableURLRequest -> setCachePolicy

NSURLRequestReturnCacheDataDontLoadは、オフラインモードにするポリシーであるように見えます。

希望に役立ちます!

+0

しかし、それは私がインターネット接続をチェックして、要求を実行し、それに応じてキャッシュポリシーを変更する必要があることを意味するのでしょうか? – Ecarrion

+0

AFHTTPClientのsetReachabilityStatusChangeBlockを調べ、ネットワークの変更を監視します。キャッシュポリシーを変更できますか?ただし、上記のようにキャッシュポリシーを設定して、必要な「オフラインモード」の動作が得られるかどうかを確認する必要があります。あなたは、オンライン/オフラインの間のあなたのスイッチングメカニズムを調べることができます。 – Dave

+1

これは何ですか、これは機能していますか? – Renetik

関連する問題