本地缓存机制之一
在手機(jī)應(yīng)用程序開(kāi)發(fā)中,為了減少與服務(wù)端的交互次數(shù),加快用戶的響應(yīng)速度,一般都會(huì)在iOS設(shè)備中加一個(gè)緩存的機(jī)制,前面一篇文章介紹了iOS設(shè)備的內(nèi)存緩存,這篇文章將設(shè)計(jì)一個(gè)本地緩存的機(jī)制。
?
功能需求
?
? ?? ? 這個(gè)緩存機(jī)制滿足下面這些功能。
?
1、可以將數(shù)據(jù)緩存到本地磁盤(pán)。
?
2、可以判斷一個(gè)資源是否已經(jīng)被緩存。如果已經(jīng)被緩存,在請(qǐng)求相同的資源,先到本地磁盤(pán)搜索。
?
3、可以判斷文件緩存什么時(shí)候過(guò)期。這里為了簡(jiǎn)單起見(jiàn)這里,我們?cè)谡?qǐng)求url資源的時(shí)候,給每次請(qǐng)求的文件設(shè)定一個(gè)過(guò)期的時(shí)間。
?
4、可以實(shí)現(xiàn):如果文件已經(jīng)被緩存,而且沒(méi)有過(guò)期,這將本地的數(shù)據(jù)返回,否則重新請(qǐng)求url。
?
5、可以實(shí)現(xiàn):如果文件下載不成功或者下載沒(méi)有完成,下次打開(kāi)程序的時(shí)候,移除這些沒(méi)有成功或者沒(méi)有下載完成的文件。
?
6、可以實(shí)現(xiàn):同時(shí)請(qǐng)求或者下載多個(gè)資源。
?
設(shè)計(jì)實(shí)現(xiàn):
?
1、設(shè)計(jì)一個(gè)CacheItem類,用來(lái)請(qǐng)求一個(gè)web連接,它的一個(gè)實(shí)例表示一個(gè)緩存項(xiàng)。這個(gè)CacheItem類,需要一個(gè)url創(chuàng)建一個(gè)NSURLConnection,去請(qǐng)求web資源。使用CacheItem類主要用來(lái)請(qǐng)求web資源。
/* ---------緩存項(xiàng)-------------- */??
? ?
@interface CacheItem : NSObject {??
@public??
? ?id<CacheItemDelegate> delegate;??
? ???//web地址??
? ?NSString? ?? ?? ?? ???*remoteURL;??
@private??
? ???//是否正在下載??
? ?BOOL? ?? ?? ?? ?? ?? ?isDownloading;??
? ?? ???//NSMutableData對(duì)象??
? ?NSMutableData? ?? ?? ?*connectionData;??
? ???//NSURLConnection對(duì)象??
? ?NSURLConnection? ?? ? *connection;??
}??
? ?
/* -------------------------- */??
? ?
@property (nonatomic, retain) id<CacheItemDelegate> delegate;??
@property (nonatomic, retain) NSString??*remoteURL;??
@property (nonatomic, assign) BOOL? ?? ?isDownloading;??
@property (nonatomic, retain) NSMutableData *connectionData;??
@property (nonatomic, retain) NSURLConnection *connection;??
? ?
/* ----------開(kāi)始下載方法----------- */??
? ?
- (BOOL) startDownloadingURL:(NSString *)paramRemoteURL;??
? ?
@end
復(fù)制代碼
2、在NSURLConnection開(kāi)始請(qǐng)求之前,調(diào)用CachedDownloadManager類,來(lái)搜索和管理本地的緩存文件。將緩存文件的情況保存到一個(gè)字典類中。這個(gè)字典設(shè)計(jì)如下:
{??
? ?"http://www.cnn.com" =? ???{??
? ???DownloadEndDate = "2011-08-02 07:51:57 +0100";??
? ???DownloadStartDate = "2011-08-02 07:51:55 +0100";??
? ???ExpiresInSeconds = 20;??
? ???ExpiryDate = "2011-08-02 07:52:17 +0100";??
? ???LocalURL = "/var/mobile/Applications/ApplicationID/Documents/??
? ?? ?? ?? ?? ???httpwww.cnn.com.cache";??
? ?};??
? ?"http://www.baidu.com" =? ???{??
? ???DownloadEndDate = "2011-08-02 07:51:49 +0100";??
? ???DownloadStartDate = "2011-08-02 07:51:44 +0100";??
? ???ExpiresInSeconds = 20;??
? ???ExpiryDate = "2011-08-02 07:52:09 +0100";??
? ???LocalURL = "/var/mobile/Applications/ApplicationID/Documents/??
? ?? ?? ?? ?? ???httpwww.oreilly.com.cache";??
? ?};??
}
復(fù)制代碼
? ?? ? 上面這個(gè)字典里面嵌套了字典。里面那層字典表示一個(gè)緩存項(xiàng)的緩存信息:下載結(jié)束時(shí)間、下載開(kāi)始時(shí)間、緩存有效時(shí)間、緩存過(guò)期時(shí)間、緩存到本地的路徑。
? ?? ? 下面看下CachedDownloadManager類。用它來(lái)實(shí)現(xiàn)和封裝我們的緩存策略。
/* -----------CachedDownloadManager-------------- */??
? ?
@interface CachedDownloadManager : NSObject? ?
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?<CacheItemDelegate> {??
@public??
? ?id<CachedDownloadManagerDelegate>??delegate;??
@private??
//記錄緩存數(shù)據(jù)的字典??
? ?NSMutableDictionary? ?? ?? ?? ?? ? *cacheDictionary;??
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? //緩存的路徑??
? ?NSString? ?? ?? ?? ?? ?? ?? ?? ?? ?*cacheDictionaryPath;??
}??
? ?
? ?
@property (nonatomic, assign)? ?
id<CachedDownloadManagerDelegate> delegate;??
? ?
@property (nonatomic, copy)? ?
NSMutableDictionary *cacheDictionary;??
? ?
@property (nonatomic, retain)? ?
NSString *cacheDictionaryPath;??
? ?
? ?
/* 保持緩存字典 */??
? ?
- (BOOL) saveCacheDictionary;??
? ?
/* 公有方法:下載 */??
? ?
- (BOOL)? ?? ?? ?download:(NSString *)paramURLAsString??
? ? urlMustExpireInSeconds:(NSTimeInterval)paramURLMustExpireInSeconds??
updateExpiryDateIfInCache:(BOOL)paramUpdateExpiryDateIfInCache;??
? ?
/* -------------------------- */??
? ?
@end
復(fù)制代碼
?
? ?? ? 從上面代碼可以看出,這個(gè)管理緩存的類中,有一個(gè)緩存字典:cacheDictionary,用來(lái)表示所有資源的緩存情 況;cacheDictionaryPath用來(lái)表示緩存的路徑;saveCacheDictionary用來(lái)將緩存字典歸檔到本地文件中。 download:urlMustExpireInSeconds:updateExpiryDateIfInCache是一個(gè)公共接口,通過(guò)傳遞 url、緩存過(guò)期時(shí)間、是否更新緩存過(guò)期時(shí)間三個(gè)參數(shù)來(lái)方便的使用,實(shí)現(xiàn)我們的緩存策略。
?
3、如果這個(gè)文件已經(jīng)被下載,而且沒(méi)有過(guò)期,則從本地獲取文件的數(shù)據(jù)。如果文件已經(jīng)過(guò)期,則重新下載。我們通過(guò)download:urlMustExpireInSeconds:updateExpiryDateIfInCache方法來(lái)實(shí)現(xiàn),主要看這個(gè)方法的代碼:
/* ---------下載-------------- */??
? ?
- (BOOL)? ?? ?? ?download:(NSString *)paramURLAsString??
? ? urlMustExpireInSeconds:(NSTimeInterval)paramURLMustExpireInSeconds??
updateExpiryDateIfInCache:(BOOL)paramUpdateExpiryDateIfInCache{??
? ???
? ?BOOL result = NO;??
? ???
? ?if (self.cacheDictionary == nil ||??
? ?? ? [paramURLAsString length] == 0){??
? ???return(NO);??
? ?}??
? ???
? ?paramURLAsString = [paramURLAsString lowercaseString];??
? ?//根據(jù)url,從字典中獲取緩存項(xiàng)的相關(guān)數(shù)據(jù)??
? ?NSMutableDictionary *itemDictionary =? ?
? ?[self.cacheDictionary objectForKey:paramURLAsString];??
? ???
? ?/* 使用下面這些變量幫助我們理解緩存邏輯 */??
? ???//文件是否已經(jīng)被緩存??
? ?BOOL? ? fileHasBeenCached = NO;??
? ???//緩存是否過(guò)期??
? ?BOOL? ? cachedFileHasExpired = NO;??
? ???//緩存文件是否存在??
? ?BOOL? ? cachedFileExists = NO;??
? ???//緩存文件能否被加載??
? ?BOOL? ? cachedFileDataCanBeLoaded = NO;??
? ???//緩存文件數(shù)據(jù)??
? ?NSData??*cachedFileData = nil;??
? ???//緩存文件是否完全下載??
? ?BOOL? ? cachedFileIsFullyDownloaded = NO;??
? ???//緩存文件是否已經(jīng)下載??
? ?BOOL? ? cachedFileIsBeingDownloaded = NO;??
? ?//過(guò)期時(shí)間??
? ?NSDate? ? *expiryDate = nil;??
? ???//下載結(jié)束時(shí)間??
? ?NSDate? ? *downloadEndDate = nil;??
? ???//下載開(kāi)始時(shí)間??
? ?NSDate? ? *downloadStartDate = nil;??
? ???//本地緩存路徑??
? ?NSString??*localURL = nil;??
? ???//有效時(shí)間??
? ?NSNumber??*expiresInSeconds = nil;??
? ?NSDate? ? *now = [NSDate date];??
? ???
? ?if (itemDictionary != nil){??
? ???fileHasBeenCached = YES;??
? ?}??
? ?//如果文件已經(jīng)被緩存,則從緩存項(xiàng)相關(guān)數(shù)據(jù)中獲取相關(guān)的值??
? ?if (fileHasBeenCached == YES){??
? ?? ??
? ???expiryDate = [itemDictionary? ?
? ?? ?? ?? ?? ?? ? objectForKey:CachedKeyExpiryDate];??
? ?? ??
? ???downloadEndDate = [itemDictionary??
? ?? ?? ?? ?? ?? ?? ?? ?objectForKey:CachedKeyDownloadEndDate];??
? ?? ??
? ???downloadStartDate = [itemDictionary??
? ?? ?? ?? ?? ?? ?? ?? ???objectForKey:CachedKeyDownloadStartDate];??
? ?? ??
? ???localURL = [itemDictionary??
? ?? ?? ?? ?? ???objectForKey:CachedKeyLocalURL];??
? ?? ??
? ???expiresInSeconds = [itemDictionary??
? ?? ?? ?? ?? ?? ?? ?? ? objectForKey:CachedKeyExpiresInSeconds];??
? ???//如果下載開(kāi)始和結(jié)束時(shí)間不為空,表示文件全部被下載??
? ???if (downloadEndDate != nil &&? ?
? ?? ?? ?downloadStartDate != nil){??
? ?? ? cachedFileIsFullyDownloaded = YES;??
? ???}??
? ?? ??
? ???/* 如果expiresInSeconds不為空,downloadEndDate為空,表示文件已經(jīng)正在下載 */??
? ???if (expiresInSeconds != nil &&??
? ?? ?? ?downloadEndDate == nil){??
? ?? ? cachedFileIsBeingDownloaded = YES;??
? ???}??
? ?? ??
? ???/* 判斷緩存是否過(guò)期 */??
? ???if (expiryDate != nil &&??
? ?? ?? ?[now timeIntervalSinceDate:expiryDate] > 0.0){??
? ?? ? cachedFileHasExpired = YES;??
? ???}??
? ?? ??
? ???if (cachedFileHasExpired == NO){??
? ?? ? /* 如果緩存文件沒(méi)有過(guò)期,加載緩存文件,并且更新過(guò)期時(shí)間 */??
? ?? ? NSFileManager *fileManager = [[NSFileManager alloc] init];??
? ?? ?? ?
? ?? ? if ([fileManager fileExistsAtPath:localURL] == YES){??
? ?? ?? ?cachedFileExists = YES;??
? ?? ?? ?cachedFileData = [NSData dataWithContentsOfFile:localURL];??
? ?? ?? ?if (cachedFileData != nil){??
? ?? ?? ???cachedFileDataCanBeLoaded = YES;??
? ?? ?? ?} /* if (cachedFileData != nil){ */??
? ?? ? } /* if ([fileManager fileExistsAtPath:localURL] == YES){ */??
? ?? ?? ?
? ?? ? [fileManager release];??
? ?? ?? ?
? ?? ? /* 更新緩存時(shí)間 */??
? ?? ?? ?
? ?? ? if (paramUpdateExpiryDateIfInCache == YES){??
? ?? ?? ???
? ?? ?? ?NSDate *newExpiryDate =? ?
? ?? ?? ?[NSDate dateWithTimeIntervalSinceNow:??
? ?? ?? ? paramURLMustExpireInSeconds];??
? ?? ?? ???
? ?? ?? ?NSLog(@"Updating the expiry date from %@ to %@.",? ?
? ?? ?? ?? ?? ?expiryDate,? ?
? ?? ?? ?? ?? ?newExpiryDate);??
? ?? ?? ???
? ?? ?? ?[itemDictionary setObject:newExpiryDate??
? ?? ?? ?? ?? ?? ?? ?? ?? ? forKey:CachedKeyExpiryDate];??
? ?? ?? ???
? ?? ?? ?NSNumber *expires =? ?
? ?? ?? ?[NSNumber numberWithFloat:paramURLMustExpireInSeconds];??
? ?? ?? ???
? ?? ?? ?[itemDictionary setObject:expires??
? ?? ?? ?? ?? ?? ?? ?? ?? ? forKey:CachedKeyExpiresInSeconds];??
? ?? ? }??
? ?? ?? ?
? ???} /* if (cachedFileHasExpired == NO){ */??
? ?? ??
? ?}??
? ???
? ?if (cachedFileIsBeingDownloaded == YES){??
? ???NSLog(@"這個(gè)文件已經(jīng)正在下載...");??
? ???return(YES);??
? ?}??
? ???
? ?if (fileHasBeenCached == YES){??
? ?? ??
? ???if (cachedFileHasExpired == NO &&??
? ?? ?? ?cachedFileExists == YES &&??
? ?? ?? ?cachedFileDataCanBeLoaded == YES &&??
? ?? ?? ?[cachedFileData length] > 0 &&??
? ?? ?? ?cachedFileIsFullyDownloaded == YES){??
? ?? ?? ?
? ?? ? /* 如果文件有緩存而且沒(méi)有過(guò)期 */??
? ?? ?? ?
? ?? ? NSLog(@"文件有緩存而且沒(méi)有過(guò)期.");??
? ?? ?? ?
? ?? ? [self.delegate? ?
? ?? ???cachedDownloadManagerSucceeded:self??
? ?? ???remoteURL:[NSURL URLWithString:paramURLAsString]??
? ?? ???localURL:[NSURL URLWithString:localURL]??
? ?? ???aboutToBeReleasedData:cachedFileData??
? ?? ???isCachedData:YES];??
? ?? ?? ?
? ?? ? return(YES);??
? ?? ?? ?
? ???} else {??
? ?? ? /* 如果文件沒(méi)有被緩存,獲取緩存失敗 */??
? ?? ? NSLog(@"文件沒(méi)有緩存.");??
? ?? ? [self.cacheDictionary removeObjectForKey:paramURLAsString];??
? ?? ? [self saveCacheDictionary];??
? ???} /* if (cachedFileHasExpired == NO && */??
? ?? ??
? ?} /* if (fileHasBeenCached == YES){ */??
? ???
? ?/* 去下載文件 */??
? ???
? ???
? ?NSNumber *expires =? ?
? ?[NSNumber numberWithFloat:paramURLMustExpireInSeconds];??
? ???
? ?NSMutableDictionary *newDictionary =? ?
? ?[[[NSMutableDictionary alloc] init] autorelease];??
? ???
? ?[newDictionary setObject:expires? ?
? ?? ?? ?? ?? ?? ?? ?forKey:CachedKeyExpiresInSeconds];??
? ???
? ???
? ?localURL = [paramURLAsString??
? ?? ?? ?? ?? ?stringByAddingPercentEscapesUsingEncoding:??
? ?? ?? ?? ?? ?NSUTF8StringEncoding];??
? ???
? ?localURL = [localURL stringByReplacingOccurrencesOfString:@"://"??
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???withString:@""];??
? ???
? ?localURL = [localURL stringByReplacingOccurrencesOfString:@"/"??
? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???withString:@"{1}quot;];??
? ???
? ?localURL = [localURL stringByAppendingPathExtension:@"cache"];??
? ???
? ?NSString *documentsDirectory =? ?
? ?[self documentsDirectoryWithTrailingSlash:NO];??
? ???
? ?localURL = [documentsDirectory? ?
? ?? ?? ?? ?? ?stringByAppendingPathComponent:localURL];??
? ???
? ?[newDictionary setObject:localURL??
? ?? ?? ?? ?? ?? ?? ?forKey:CachedKeyLocalURL];??
? ???
? ?[newDictionary setObject:now??
? ?? ?? ?? ?? ?? ?? ?forKey:CachedKeyDownloadStartDate];??
? ???
? ?[self.cacheDictionary setObject:newDictionary??
? ?? ?? ?? ?? ?? ?? ?? ?? ? forKey:paramURLAsString];??
? ???
? ?[self saveCacheDictionary];??
? ???
? ?CacheItem *item = [[[CacheItem alloc] init] autorelease];??
? ?[item setDelegate:self];??
? ?[item startDownloadingURL:paramURLAsString];??
? ???
? ?return(result);??
? ???
}
文章來(lái)源:http://www.cnblogs.com/pengyingh/articles/2343039.html
分類: iOS
轉(zhuǎn)載于:https://blog.51cto.com/9077272/1428594
總結(jié)
- 上一篇: Toad 补充与培训 常用菜单
- 下一篇: 如何在servlet刚启动时候获取服务器