已解决和更新的代码。
我已经实现了一个将图像缓存到磁盘的图像缓存。它的工作原理是将UIImage存档到NSData
并使用[data writeToFile:path options:NSDataWritingAtomic error:&error]
写入磁盘,其中path是imageURL(从'/'条带化,因此它不会被误认为是目录)。除此之外还有一个字典,键是imageURL
,值是时间戳,所以如果字典满了,我可以删除最旧的图像。这是这一切的基本功能。
问题: 一切都运作良好一段时间(看似随机的场合)我得到这个错误:
-[__NSCFType encodeWithCoder:]: unrecognized selector sent to instance 0x16eaf810
在这一行(NSData * registerData = ...)中的方法如下:
- (void)persistData:(UIImage *)image forKey:(NSString *)key
{
@synchronized(self) { // looks like this have no effect
NSData *imageData = [NSKeyedArchiver archivedDataWithRootObject:image];
[NSFileManager THSNstoreData:imageData forKey:key];
NSData *registerData = [NSKeyedArchiver archivedDataWithRootObject:_imageCacheRegister]; // debugger stops here
[NSFileManager THSNstoreData:registerData forKey:_dictionaryKey];
}
}
我已手动检查字典,字典或其任何键/值的地址与错误消息中实例的地址不同。
我真的很困惑......根据我读过的一些内容,当内存被回收时使用了__NSCFType
。所以这意味着某些东西会被释放到早期......或者完全不同的东西。
非常感谢任何帮助。
更新 我当然正在使用ARC。还有一个依赖注入框架,使我能够将其用作单例。
以下是该类中的所有代码:
#import "ImageDiskCache.h"
#import "NSMutableDictionary+Techsson.h"
@interface ImageDiskCache () {
NSString *_dictionaryKey;
NSMutableDictionary *_imageCacheRegister;
dispatch_queue_t _diskQue;
NSInteger _maxCachedImagesCount;
NSInteger _numberOfImagesToRemove;
}
@end
@implementation ImageDiskCache
- (id)init
{
self = [super init];
if (self) {
_maxCachedImagesCount = 50;
_numberOfImagesToRemove = 5;
_dictionaryKey = @"cacheRegistry";
_diskQue = dispatch_queue_create("diskQue", NULL);
dispatch_async(_diskQue, ^{
NSData *data = [NSFileManager THSNdataForKey:_dictionaryKey];
if ( data )
{
_imageCacheRegister = [NSKeyedUnarchiver unarchiveObjectWithData:data];
}
else
{
_imageCacheRegister = [[NSMutableDictionary alloc] initWithCapacity:_maxCachedImagesCount];
}
});
}
return self;
}
- (void)readImageForKey:(NSString *)key withCompletionHandler:(UIImageCompletionHandler)completion
{
if ( _imageCacheRegister && key )
{
dispatch_async(_diskQue, ^{
NSString *stripedKey = [self stripedKeyForKey:key];
if ( [_imageCacheRegister safeObjectForKey:stripedKey] )
{
NSData *imageData = [NSFileManager THSNdataForKey:stripedKey];
UIImage *image = imageData ? [NSKeyedUnarchiver unarchiveObjectWithData:imageData] : nil;
dispatch_async(dispatch_get_main_queue(), ^{
completion(image);
});
}
else
{
completion(nil);
}
});
}
else
{
completion(nil);
}
}
- (void)wrightImage:(UIImage *)image forKey:(NSString *)key
{
if ( !image || !key || [key isEqualToString:@""] || !_imageCacheRegister )
{
return;
}
dispatch_async(_diskQue, ^{
NSString *stripedKey = [self stripedKeyForKey:key];
if ( [_imageCacheRegister safeCount] < _maxCachedImagesCount )
{
[_imageCacheRegister safeSetObject:[self timeStampAsData] forKey:stripedKey];
[self persistData:image forKey:stripedKey];
}
else
{
NSArray *keys = [_imageCacheRegister safeKeysSortedByValueUsingComparator:^NSComparisonResult(id obj1, id obj2) {
NSTimeInterval timeStampObj1 = [self timeStampFromData:obj1];
NSTimeInterval timeStampObj2 = [self timeStampFromData:obj2];
if ( timeStampObj1 > timeStampObj2 )
{
return (NSComparisonResult)NSOrderedAscending;
}
else if ( timeStampObj1 < timeStampObj2 )
{
return (NSComparisonResult)NSOrderedDescending;
}
return (NSComparisonResult)NSOrderedSame;
}];
NSArray *toRemove = [keys subarrayWithRange:NSMakeRange([keys count] - _numberOfImagesToRemove, _numberOfImagesToRemove)];
[_imageCacheRegister safeRemoveObjectsForKeys:toRemove];
for ( NSString *k in toRemove )
{
[NSFileManager THSNdeleteDataForKey:k];
}
[_imageCacheRegister safeSetObject:[self timeStampAsData] forKey:stripedKey];
[self persistData:image forKey:stripedKey];
}
});
}
#pragma - private methods
- (NSString *)stripedKeyForKey:(NSString *)key
{
NSString *stripedKey = [key stringByReplacingOccurrencesOfString:@"/" withString:@""];
return stripedKey;
}
- (NSData *)timeStampAsData
{
NSTimeInterval timeStamp = [[NSDate date] timeIntervalSince1970];
NSData *timeStampData = [NSData dataWithBytes:&timeStamp length:sizeof(NSTimeInterval)];
return timeStampData;
}
- (NSTimeInterval)timeStampFromData:(NSData *)timeStampData
{
NSTimeInterval timeStamp;
[timeStampData getBytes:&timeStamp length:sizeof(NSTimeInterval)];
return timeStamp;
}
- (void)persistData:(UIImage *)image forKey:(NSString *)key
{
// @synchronized(self) {
NSData *imageData = [NSKeyedArchiver archivedDataWithRootObject:image];
[NSFileManager THSNstoreData:imageData forKey:key];
NSData *registerData = [NSKeyedArchiver archivedDataWithRootObject:_imageCacheRegister];
[NSFileManager THSNstoreData:registerData forKey:_dictionaryKey];
// }
}
答案 0 :(得分:0)
也许是因为你在使用可变数据? NSKeyedArchiver有不同的方法
- (id)initForWritingWithMutableData:(NSMutableData *)data
试试这个方法
- (void)persistData:(UIImage *)image forKey:(NSString *)key
{
@synchronized(self) {
NSData *imageData = [NSKeyedArchiver archivedDataWithRootObject:image];
[NSFileManager THSNstoreData:imageData forKey:key];
NSMutableData *registerData = [[NSMutableData alloc] init];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:registerData];
[archiver encodeObject:_imageCacheRegister forKey:@"root"];
[archiver finishEncoding];
[NSFileManager THSNstoreData:registerData forKey:_dictionaryKey];
}
}
希望有助于交配