gpt4 book ai didi

iphone - 带有 AFNetworking 和离线模式的 SDURLCache 不起作用

转载 作者:IT老高 更新时间:2023-10-28 11:48:23 25 4
gpt4 key购买 nike

我正在使用 AFNetworkingSDURLCache 进行所有网络操作。

我的 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,根据苹果文档,它的工作方式如下:

If an NSCachedURLResponse does not exist for the request, then the data is fetched from the originating source. If there is a cached response for the request, the URL loading system checks the response to determine if it specifies that the contents must be revalidated. If the contents must be revalidated a connection is made to the originating source to see if it has changed. If it has not changed, then the response is returned from the local cache. If it has changed, the data is fetched from the originating source.

If the cached response doesn’t specify that the contents must be revalidated, the maximum age or expiration specified in the response is examined. If the cached response is recent enough, then the response is returned from the local cache. If the response is determined to be stale, the originating source is checked for newer data. If newer data is available, the data is fetched from the originating source, otherwise it is returned from the cache.

因此,只要缓存没有过期,即使在飞行模式下,一切也能完美运行。当缓存过期(max-age 等)时,会调用失败 block 。

我一直在 SDURLCache 内部挖掘一点,这个方法返回一个包含有效数据的响应(我已经将数据解析为一个字符串,它包含缓存的信息)

- (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;
}

所以此时我不知道该怎么做,因为我相信响应是由操作系统处理的,然后 AFNetworking 收到一个

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

AFURLConnectionOperation内。

最佳答案

好吧,我终于找到了一个不那么难看的解决方法:

第一

如果您使用的是 IOS5/IOS6,您可以删除 SDURLCache 并使用 native :

//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;
}

有了这些代码,我们现在可以检测 wifi/3g 何时不可用,并指定无论如何始终使用缓存的请求。 (离线模式)

备注

  • networkReachabilityStatusAFNetworkReachabilityStatusUnknown 时,我仍然不知道该怎么办。这可能发生在应用程序启动后立即发出请求并且 AF尚未获得互联网状态。

  • 请记住,为了使其正常工作,服务器必须在 http 响应中设置正确的缓存 header 。

更新

看起来IOS6在没有网络的情况下加载缓存响应有些问题,所以即使请求被缓存并且请求缓存策略设置为NSURLRequestReturnCacheDataDontLoad,请求也会失败。

所以一个丑陋的解决方法是修改 (void)connection:(NSURLConnection __unused *)connection
didFailWithError:(NSError *)error
in AFURLConnectionOperation.m 用于在请求失败时检索缓存的响应,但仅限于特定的缓存策略。

- (void)connection:(NSURLConnection __unused *)connection
didFailWithError:(NSError *)error
{
self.error = error;

[self.outputStream close];

[self finish];

self.connection = nil;

//Ugly hack for making the request succeed if we can find a valid non-empty cached request
//This is because IOS6 is not handling cache responses right when we are in a no-connection sittuation
//Only use this code for cache policies that are supposed to listen to cache regarding it's expiration date
if (self.request.cachePolicy == NSURLRequestUseProtocolCachePolicy ||
self.request.cachePolicy == NSURLRequestReturnCacheDataElseLoad ||
self.request.cachePolicy == NSURLRequestReturnCacheDataDontLoad) {

NSCachedURLResponse * cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:self.request];
if (cachedResponse.data.length > 0) {
self.responseData = cachedResponse.data;
self.response = cachedResponse.response;
self.error = nil;
}
}
}

关于iphone - 带有 AFNetworking 和离线模式的 SDURLCache 不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10250055/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com