存档时出现运行时错误NSMutableDictionary
问题描述:
求解和更新的代码。存档时出现运行时错误NSMutableDictionary
我已经实现了将图像缓存到磁盘的图像缓存。它的工作原理是将UIImage存档为NSData
并将其写入磁盘,其中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];
// }
}
答
也许是因为你使用的可变数据?的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];
}
}
希望帮助队友
感谢您的帮助。我明天会试试这个结果并报告结果。 –
感谢您的建议,但这对问题没有影响。我已经将更多的代码放在_diskOne队列中,现在问题似乎已解决。我不确定,但现在我没有得到任何崩溃..但。 –
也许是因为你正在执行另一个线程,指针会不时被释放,而对象本身仍然保留?似乎问题可能取决于队列中堆叠的较低优先级进程的数量,从而导致延迟太长?只是有些想法,但很高兴你已经解决了这个问题 – GroovyCarrot