I built a VERY simple cache class for my iOS app yet while it seems to save the data given to it it’s never able to retrieve it. My Cache system should work by creating a CachedObject that stores the Object to cache, the key, and an expiration date. It then should archive that object and save to a file named key.cache.
Cache.h
#import <Foundation/Foundation.h>
@interface Cache : NSObject
+(void)setValue:(NSObject<NSCoding> *)value forKey:(NSString *)key expires:(NSDate *)expire;
+(NSObject<NSCoding> *)getValueFromKey:(NSString *)key;
@end
Cache.m
#import "Cache.h"
#import "CachedObject.h"
#define CACHE_LOCATION @"Library/test"
@implementation Cache
+(void)setValue:(NSObject<NSCoding> *)value forKey:(NSString *)key expires:(NSDate *)expire
{
if ((value == nil) || (key == nil))
{
return;
}
CachedObject *obj = [[CachedObject alloc] initWithObject:value expires:expire forKey:key];
NSError *error;
if (![[NSFileManager defaultManager] createDirectoryAtPath:CACHE_LOCATION withIntermediateDirectories:YES attributes:nil error:&error])
{
[error release];
return;
}
NSString *fileName = [[NSString alloc] initWithFormat:@"%@.cache", key];
NSString *fileFullPath = [CACHE_LOCATION stringByAppendingPathComponent:fileName];
[NSKeyedArchiver archiveRootObject:obj toFile:fileFullPath];
[fileName release];
[obj release];
}
+(NSObject<NSCoding> *)getValueFromKey:(NSString *)key
{
NSString *fileName = [[NSString alloc] initWithFormat:@"%@.cache", key];
NSString *fileFullPath = [CACHE_LOCATION stringByAppendingPathComponent:fileName];
CachedObject *obj = [NSKeyedUnarchiver unarchiveObjectWithFile:fileFullPath];
NSDate *today = [NSDate date];
if ((obj != nil) && (obj.expires != nil) && ([obj.expires compare:today] != NSOrderedAscending))
{
obj = nil;
}
[fileName release];
if (obj != nil)
{
obj = [obj autorelease];
}
return obj;
}
@end
CachedObject.h
#import <Foundation/Foundation.h>
@interface CachedObject : NSObject<NSCoding>
{
NSObject<NSCoding> *_object;
NSDate *_expires;
NSString *_key;
}
@property (readonly) NSObject<NSCoding> *object;
@property (readonly) NSDate *expires;
@property (readonly) NSString *key;
-(id)initWithObject:(NSObject<NSCoding> *)aObject expires:(NSDate *)aExpires forKey:(NSString *)aKey;
@end
CachedObject.m
#import "CachedObject.h"
#define EXPIRE_KEY @"expires"
#define KEY_KEY @"key"
@implementation CachedObject
@synthesize object = _object;
@synthesize expires = _expires;
@synthesize key = _key;
-(void)encodeWithCoder:(NSCoder *)aCoder
{
[_object encodeWithCoder:aCoder];
[aCoder encodeObject:_expires forKey:EXPIRE_KEY];
[aCoder encodeObject:_key forKey:KEY_KEY];
}
-(id)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super init])
{
_object = [_object initWithCoder:aDecoder];
if (self.object == nil)
{
return nil;
}
_expires = [[aDecoder decodeObjectForKey:EXPIRE_KEY] retain];
_key = [[aDecoder decodeObjectForKey:KEY_KEY] retain];
}
return self;
}
-(id)initWithObject:(NSObject<NSCoding> *)aObject expires:(NSDate *)aExpires forKey:(NSString *)aKey
{
if (self = [super init])
{
_object = aObject;
_expires = aExpires;
_key = aKey;
}
return self;
}
@end
I think part of the issue might be the way you’re serializing your
_objectinstance variable insideCachedObject.m(Perhaps any NSCoding experts can prove me wrong?)I think instead of:
You want to use:
Since you want to treat
_objectas an instance variable, similar to your_expiresand_keyobjects.Side Note: When autoreleasing objects, you don’t need to do this:
You can just do: