使用NSCache实现缓存过期实现

Boo*_*oon 10 cocoa-touch caching

我正在使用NSCache在我的应用程序中实现缓存.我想为它添加过期,以便在一段时间后获取新数据.有哪些选择以及最佳方法是什么?

我应该查看访问缓存时的时间戳并使其无效吗?缓存是否应使用固定间隔计时器自动使自身无效?

Aar*_*ger 8

缓存是否应使用固定间隔计时器自动使自身无效?

这将是一个糟糕的解决方案,因为您可能会在计时器触发前添加几秒钟.到期时间应基于特定项目的年龄.(当然,可以使用计时器有条件地使项目无效;请参阅此答案的评论.)

这是一个例子.我考虑过继承NSCache,但决定使用组合更简单.

接口

//
//  ExpiringCache.h
//
//  Created by Aaron Brager on 10/23/13.

#import <Foundation/Foundation.h>

@protocol ExpiringCacheItem <NSObject>

@property (nonatomic, strong) NSDate *expiringCacheItemDate;

@end

@interface ExpiringCache : NSObject

@property (nonatomic, strong) NSCache *cache;
@property (nonatomic, assign) NSTimeInterval expiryTimeInterval;

- (id)objectForKey:(id)key;
- (void)setObject:(NSObject <ExpiringCacheItem> *)obj forKey:(id)key;

@end
Run Code Online (Sandbox Code Playgroud)

履行

//
//  ExpiringCache.m
//
//  Created by Aaron Brager on 10/23/13.

#import "ExpiringCache.h"

@implementation ExpiringCache

- (instancetype) init {
    self = [super init];

    if (self) {
        self.cache = [[NSCache alloc] init];
        self.expiryTimeInterval = 3600;  // default 1 hour
    }

    return self;
}

- (id)objectForKey:(id)key {
    @try {
        NSObject <ExpiringCacheItem> *object = [self.cache objectForKey:key];

        if (object) {
            NSTimeInterval timeSinceCache = fabs([object.expiringCacheItemDate timeIntervalSinceNow]);
            if (timeSinceCache > self.expiryTimeInterval) {
                [self.cache removeObjectForKey:key];
                return nil;
            }
        }

        return object;
    }

    @catch (NSException *exception) {
        return nil;
    }
}

- (void)setObject:(NSObject <ExpiringCacheItem> *)obj forKey:(id)key {
    obj.expiringCacheItemDate = [NSDate date];
    [self.cache setObject:obj forKey:key];
}

@end
Run Code Online (Sandbox Code Playgroud)

笔记

  • 假设你正在使用ARC.
  • 我没有实现,setObject:forKey:cost:因为NSCache文档只是告诉你不要使用它.
  • 我使用@ try/@ catch块,因为从技术上讲,您可以将一个对象添加到不响应的缓存中expiringCacheItemDate.我考虑过使用respondsToSelector:这个,但你可以添加一个对此不响应的对象,因为NSCache需要id而不是NSObject.

示例代码

#import "ExpiringCache.h"

@property (nonatomic, strong) ExpiringCache *accountsCache;

- (void) doSomething {
    if (!self.accountsCache) {
        self.accountsCache = [[ExpiringCache alloc] init];
        self.accountsCache.expiryTimeInterval = 7200; // 2 hours
    }

    // add an object to the cache
    [self.accountsCache setObject:newObj forKey:@"some key"];

    // get an object
    NSObject *cachedObj = [self.accountsCache objectForKey:@"some key"];
    if (!cachedObj) {
        // create a new one, this one is expired or we've never gotten it
    }
}
Run Code Online (Sandbox Code Playgroud)