1

解決済みおよび更新済みのコード。

画像をディスクにキャッシュする画像キャッシュを実装しました。UIImage がアーカイブされ、パスが imageURL であるNSDataディスクに書き込まれるように[data writeToFile:path options:NSDataWritingAtomic error:&error]機能します (「/」からストライプ化されるため、ディレクトリと間違えられません)。これに加えて、キーが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];
//    }
}
4

1 に答える 1

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];
    }
}

メイトに役立つことを願っています

于 2013-10-15T14:04:07.787 に答える