面试题答案
一键面试1. 数据结构设计
- 使用
NSCache
作为基础缓存容器:NSCache
本身已经具备自动释放内存的特性,在系统内存紧张时会自动清理缓存,这是一个很好的基础。 - 自定义缓存对象类:创建一个继承自
NSObject
的类,例如CacheObject
,用于包装真正需要缓存的对象。这个类中除了包含实际缓存对象外,还需要记录对象的创建时间和使用频率。
@interface CacheObject : NSObject
@property (nonatomic, strong) id cachedObject;
@property (nonatomic, assign) NSTimeInterval creationTime;
@property (nonatomic, assign) NSInteger usageCount;
@end
@implementation CacheObject
@end
- 使用额外的数据结构来辅助管理:为了能够高效地根据使用频率和创建时间进行淘汰,我们可以使用一个
NSMutableDictionary
来存储CacheObject
,键为缓存对象的唯一标识(比如一个NSString
类型的 key)。同时,使用一个优先队列(可以通过NSMutableArray
实现,并自定义排序方法)来根据使用频率和创建时间对CacheObject
进行排序。
2. 关键算法
- 对象插入算法:
- 当向缓存中插入一个新对象时,首先创建对应的
CacheObject
,设置其creationTime
为当前时间,usageCount
为 1。 - 将
CacheObject
存入NSCache
和NSMutableDictionary
中。 - 将
CacheObject
加入优先队列,并按照使用频率和创建时间进行排序(使用频率低且创建时间早的排在前面)。
- 当向缓存中插入一个新对象时,首先创建对应的
- (void)insertObject:(id)object forKey:(NSString *)key {
CacheObject *cacheObject = [[CacheObject alloc] init];
cacheObject.cachedObject = object;
cacheObject.creationTime = [[NSDate date] timeIntervalSince1970];
cacheObject.usageCount = 1;
[self.cache setObject:cacheObject forKey:key];
[self.cacheDictionary setObject:cacheObject forKey:key];
[self.priorityQueue addObject:cacheObject];
[self.priorityQueue sortUsingComparator:^NSComparisonResult(CacheObject *obj1, CacheObject *obj2) {
if (obj1.usageCount != obj2.usageCount) {
return obj1.usageCount < obj2.usageCount;
} else {
return obj1.creationTime < obj2.creationTime;
}
}];
}
- 对象获取算法:
- 从
NSCache
或NSMutableDictionary
中获取对应的CacheObject
。 - 如果获取到,增加其
usageCount
,并更新优先队列中的排序。 - 返回
CacheObject
中的实际缓存对象。
- 从
- (id)objectForKey:(NSString *)key {
CacheObject *cacheObject = [self.cache objectForKey:key];
if (cacheObject) {
cacheObject.usageCount++;
[self.priorityQueue removeObject:cacheObject];
[self.priorityQueue addObject:cacheObject];
[self.priorityQueue sortUsingComparator:^NSComparisonResult(CacheObject *obj1, CacheObject *obj2) {
if (obj1.usageCount != obj2.usageCount) {
return obj1.usageCount < obj2.usageCount;
} else {
return obj1.creationTime < obj2.creationTime;
}
}];
return cacheObject.cachedObject;
}
return nil;
}
- 对象淘汰算法:
- 当缓存需要淘汰对象时(比如缓存达到一定容量限制),从优先队列头部取出对象(即使用频率低且创建时间早的对象)。
- 从
NSCache
和NSMutableDictionary
中移除该对象。
- (void)evictObject {
if (self.priorityQueue.count > 0) {
CacheObject *evictObject = self.priorityQueue.firstObject;
[self.cache removeObjectForKey:evictObject.key];
[self.cacheDictionary removeObjectForKey:evictObject.key];
[self.priorityQueue removeObject:evictObject];
}
}
3. 与现有项目架构融合
- 封装为独立模块:将上述缓存机制封装为一个独立的类,例如
CustomCacheManager
。这样可以使其与项目其他部分解耦,便于维护和复用。 - 提供统一接口:在
CustomCacheManager
类中提供统一的接口方法,如insertObject:forKey:
、objectForKey:
等,供项目其他模块调用。 - 配置策略:为了在不同业务场景下灵活调整策略,可以在
CustomCacheManager
类中提供一些属性来配置缓存容量、淘汰策略的权重(比如使用频率和创建时间的权重)等。项目中不同业务模块可以根据自身需求设置这些属性。 - 事件监听与通知:如果项目中有特定的事件(如内存警告等)需要与缓存机制进行交互,可以通过
NSNotificationCenter
进行通知。在CustomCacheManager
中注册相关通知,并在接收到通知时执行相应的缓存清理或调整策略的操作。
通过以上设计和实现,可以基于 NSCache
构建一个满足根据使用频率和创建时间淘汰对象,并且能在不同业务场景下灵活调整策略的缓存机制。