EGOCache 소스 분석
EGOCache는 간단하고 스레드가 안전한 건-값(key-value) 기반 캐시 프레임워크로 NSString, UI/NSImage와 NSData를 지원하며 프로토콜을 실현하는 모든 종류를 저장하여 캐시 만료 시간(기본값은 1일)을 설정할 수 있다.디스크 캐시만 제공되고 메모리 캐시는 제공되지 않습니다.
두 가지 질문 코드를 가지고 읽을 수 있습니다: EGOCache는 어떻게 캐시를 진행합니까?캐시 만료는 어떻게 감지합니까?
2. 코드 분석
- (instancetype)init {
NSString* cachesDirectory = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
NSString* oldCachesDirectory = [[[cachesDirectory stringByAppendingPathComponent:[[NSProcessInfo processInfo] processName]] stringByAppendingPathComponent:@"EGOCache"] copy];
if([[NSFileManager defaultManager] fileExistsAtPath:oldCachesDirectory]) {
[[NSFileManager defaultManager] removeItemAtPath:oldCachesDirectory error:NULL];
}
cachesDirectory = [[[cachesDirectory stringByAppendingPathComponent:[[NSBundle mainBundle] bundleIdentifier]] stringByAppendingPathComponent:@"EGOCache"] copy];
return [self initWithCacheDirectory:cachesDirectory];
}
구분 방법 중의 세 개의 대기열을 주의하십시오:캐시 항목에 대한 작업을 위한 cacheInfoQueue 동기화 대기열frozenCacheInfoQueue 동기화 대기열, frozenCacheInfo에 대한 작업, frozenCacheInfo와cacheInfo의 차이점은 전자는 변할 수 없다는 것이다. 매번cacheInfo 내용이 업데이트된 후frozenCacheInfo에 동기화되어 사용자 캐시 항목에서 읽은 데이터가 작업 중인 것이 없고 데이터의 안전과 일치성을 확보합니다.diskQueue 병렬 대기열은 파일을 복사하고 파일 데이터를 쓰며 키에 따라 파일을 제거합니다.
전역 동기화 대기열이 새 라인을 열지 않았습니다. 직렬 실행입니다.전역 병발 비동기 대기열에 새로운 라인이 열려 있어 병발 실행이 가능합니다.수동으로 만든 직렬 동기화 대기열이 새 라인을 열지 않았습니다. 직렬 실행입니다.수동으로 만든 직렬 비동기 대기열에 새 스레드 1개가 열려 있습니다. 직렬 실행입니다.
- (instancetype)initWithCacheDirectory:(NSString*)cacheDirectory {
if((self = [super init])) {
_cacheInfoQueue = dispatch_queue_create("com.enormego.egocache.info", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t priority = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_set_target_queue(priority, _cacheInfoQueue);
_frozenCacheInfoQueue = dispatch_queue_create("com.enormego.egocache.info.frozen", DISPATCH_QUEUE_SERIAL);
priority = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_set_target_queue(priority, _frozenCacheInfoQueue);
_diskQueue = dispatch_queue_create("com.enormego.egocache.disk", DISPATCH_QUEUE_CONCURRENT);
priority = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_set_target_queue(priority, _diskQueue);
//
_directory = cacheDirectory;
//
_cacheInfo = [[NSDictionary dictionaryWithContentsOfFile:cachePathForKey(_directory, @"EGOCache.plist")] mutableCopy];
if(!_cacheInfo) {
_cacheInfo = [[NSMutableDictionary alloc] init];
}
//
[[NSFileManager defaultManager] createDirectoryAtPath:_directory withIntermediateDirectories:YES attributes:nil error:NULL];
// NSTimeInterval
NSTimeInterval now = [[NSDate date] timeIntervalSinceReferenceDate];
NSMutableArray* removedKeys = [[NSMutableArray alloc] init];
// plist , : , , plist key
for(NSString* key in _cacheInfo) {
if([_cacheInfo[key] timeIntervalSinceReferenceDate] <= now) {
[[NSFileManager defaultManager] removeItemAtPath:cachePathForKey(_directory, key) error:NULL];
[removedKeys addObject:key];
}
}
[_cacheInfo removeObjectsForKeys:removedKeys];
// plist
self.frozenCacheInfo = _cacheInfo;
// :1
[self setDefaultTimeoutInterval:86400];
}
return self;
}
- (NSString*)stringForKey:(NSString*)key {
return [[NSString alloc] initWithData:[self dataForKey:key] encoding:NSUTF8StringEncoding];
}
- (NSData*)dataForKey:(NSString*)key {
//
if([self hasCacheForKey:key]) {
return [NSData dataWithContentsOfFile:cachePathForKey(_directory, key) options:0 error:NULL];
} else {
return nil;
}
}
- (BOOL)hasCacheForKey:(NSString*)key {
NSDate* date = [self dateForKey:key];
if(date == nil) return NO;
//
if([date timeIntervalSinceReferenceDate] < CFAbsoluteTimeGetCurrent()) return NO;
return [[NSFileManager defaultManager] fileExistsAtPath:cachePathForKey(_directory, key)];
}
- (void)removeCacheForKey:(NSString*)key {
//
CHECK_FOR_EGOCACHE_PLIST();
dispatch_async(_diskQueue, ^{
[[NSFileManager defaultManager] removeItemAtPath:cachePathForKey(_directory, key) error:NULL];
});
[self setCacheTimeoutInterval:0 forKey:key];
}
- (void)clearCache {
dispatch_sync(_cacheInfoQueue, ^{
for(NSString* key in _cacheInfo) {
[[NSFileManager defaultManager] removeItemAtPath:cachePathForKey(_directory, key) error:NULL];
}
[_cacheInfo removeAllObjects];
dispatch_sync(_frozenCacheInfoQueue, ^{
self.frozenCacheInfo = [_cacheInfo copy];
});
[self setNeedsSave];
});
}
- (void)setCacheTimeoutInterval:(NSTimeInterval)timeoutInterval forKey:(NSString*)key {
NSDate* date = timeoutInterval > 0 ? [NSDate dateWithTimeIntervalSinceNow:timeoutInterval] : nil;
// Temporarily store in the frozen state for quick reads
// frozenCacheInfo ,
dispatch_sync(_frozenCacheInfoQueue, ^{
NSMutableDictionary* info = [self.frozenCacheInfo mutableCopy];
if(date) {
// ,
info[key] = date;
} else {
// ,
[info removeObjectForKey:key];
}
self.frozenCacheInfo = info;
});
// Save the final copy (this may be blocked by other operations)
dispatch_async(_cacheInfoQueue, ^{
if(date) {
_cacheInfo[key] = date;
} else {
[_cacheInfo removeObjectForKey:key];
}
dispatch_sync(_frozenCacheInfoQueue, ^{
self.frozenCacheInfo = [_cacheInfo copy];
});
// EGOCache.plist
[self setNeedsSave];
});
}
- (void)setNeedsSave {
//
dispatch_async(_cacheInfoQueue, ^{
if(_needsSave) return;
_needsSave = YES;
double delayInSeconds = 0.5;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, _cacheInfoQueue, ^(void){
if(!_needsSave) return;
[_cacheInfo writeToFile:cachePathForKey(_directory, @"EGOCache.plist") atomically:YES];
_needsSave = NO;
});
});
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.