您的位置:

YYCache:iOS高性能缓存框架

一、YYCache线程安全吗

YYCache是线程安全的,采用了PthreadMutex进行加锁。具体实现如下:

@implementation YYMemoryCache {
    pthread_mutex_t _lock;
    OSSpinLock _spinLock;
    ...
}

- (instancetype)init {
    if (self = [super init]) {
        pthread_mutex_init(&_lock, NULL);
        _spinLock = OS_SPINLOCK_INIT;
        ...
    }
    return self;
}

...

- (id)objectForKey:(id)key {
    if (!key) return nil;
    _lockForSafe();
    YYMemoryCacheNode *node = CFDictionaryGetValue(_dic, (__bridge const void *)(key));
    ...
    _unlockForSafe();
    ...
}

- (void)removeAllObjects {
    _lockForSafe();
    CFDictionaryRemoveAllValues(_dic);
    ...
    _unlockForSafe();
    ...
}

...

@end

通过使用PthreadMutex加锁和解锁,保证了在多线程环境下YYCache的正常运行。

二、YYCache面试题

以下是一个面试题,可以用来考察候选人YYCache的了解程度:

如何使用YYCache实现一个带有过期时间的缓存?

答案:

YYCache *cache = [[YYCache alloc] initWithName:@"myCache"];
cache.memoryCache.shouldRemoveAllObjectsOnMemoryWarning = YES;
cache.memoryCache.shouldRemoveAllObjectsWhenEnteringBackground = YES;

NSString *key = @"myKey";
NSData *value = UIImagePNGRepresentation([UIImage imageNamed:@"testImage"]);
NSTimeInterval timeInterval = 60 * 60; // 1 hour
[cache setObject:value forKey:key withBlock:^{
    NSLog(@"set object for key:%@ sucessfully", key);
} withExpirationTime:timeInterval];

[cache containsObjectForKey:key withBlock:^(NSString *key, BOOL containsObject) {
    if (containsObject) {
        [cache objectForKey:key withBlock:^(NSString *key, id object) {
            NSLog(@"get object for key:%@, value:%@", key, object);
        }];
    } else {
        NSLog(@"no object for key:%@", key);
    }
}];

首先,我们创建一个带有名称的YYCache对象,然后设置内存缓存中的对象当系统内存警告或者应用进入后台时是否需要清空。接着我们定义一个key,和要缓存的数据value,以及设置缓存的过期时间timeInterval。最后我们把value对象存储进cache中,并在存储之后打印成功的log。接着使用containsObjectForKey方法判断缓存中是否包含该key对应的缓存对象,如果包含则通过objectForKey方法获取该缓存对象并打印。

三、YYCache 磁盘增长bug

在YYCache之前的版本存在一个磁盘增长bug,当缓存达到磁盘容量上限时,缓存框架会一直增长直到磁盘被填满,导致应用崩溃。

这个问题已经在最新版本中得到解决,现代化的磁盘缓存系统从磁盘删除旧的缓存数据文件来让新的数据存放到磁盘上。

以下是解决问题的代码:

- (NSMutableDictionary *)_loadCacheMetadata {
    NSData *data = [NSData dataWithContentsOfFile:_metadataFilePath];
    NSMutableDictionary *metadata = NULL;
    ...
    if (metadata) {
        return metadata;
    } else {
        //修复磁盘中缓存信息不对导致磁盘增长bug
        [[NSFileManager defaultManager] removeItemAtPath:_metadataFilePath error:NULL];
        return @{};
    }
}

通过在_loadCacheMetadata方法中找到缓存元数据是否存在的代码,如果不存在则删除该元数据,从而解决了磁盘增长问题。

四、YYCache适用范围

YYCache适用于需要缓存的数据量较大的场景,并且在多线程环境的下运行良好。多种数据类型都可以使用YYCache进行缓存,包括UIImage,NSData,NSDictionary等。

在实际项目中,我们可以使用YYCache进行网络数据的缓存,进而提高应用程序的性能,同时可以通过设置缓存时间来进行数据的有效期控制。