存档时出现运行时错误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]; 
    } 
} 

希望帮助队友

+0

感谢您的帮助。我明天会试试这个结果并报告结果。 –

+0

感谢您的建议,但这对问题没有影响。我已经将更多的代码放在_diskOne队列中,现在问题似乎已解决。我不确定,但现在我没有得到任何崩溃..但。 –

+0

也许是因为你正在执行另一个线程,指针会不时被释放,而对象本身仍然保留?似乎问题可能取决于队列中堆叠的较低优先级进程的数量,从而导致延迟太长?只是有些想法,但很高兴你已经解决了这个问题 – GroovyCarrot