iOS 本地缓存 归档数据模型化 .m

//

//  JKCoding.h

//  runtimeTest

//

//  Created by wangdan on 15/6/24.

//  Copyright (c) 2015 wangdan. All rights reserved.

//


#ifndef runtimeTest_JKCoding_h

#define runtimeTest_JKCoding_h

#import <objc/runtime.h>

#import "NSObject+JKCoding.h"



/**

 * .m文件中使用下面的宏,可以代替手写归档协议方法,支持

 * 继承类,对象嵌套以及字典、数组中持有对象

 *

 * 使用步骤:

 * 1 在所有需要归档的对象的.m文件中,引入该头文件

 *

 * 2.在相应的.m文件中,加入宏定义 #define JKClass XXX

 * XXX 为当前类的类名

 *

 * 3.在需要归档的类的实现中,添加 JKCodingImplemention

 */


#define JKCodingImplemention \

- (void)encodeWithCoder:(NSCoder *)aCoder\

{\

    if ([JKClass superclass] != [NSObject class]) {\

        [super encodeWithCoder:aCoder];\

    }\

   unsigned int count = 0;\

   objc_property_t *pList = class_copyPropertyList([JKClass class], &count);\

    for (int i=0; i <count; i++) {\

        NSString *key= [NSString stringWithFormat:@"%s", property_getName(pList[i])];\

        [aCoder encodeObject:[self valueForKey:key] forKey:key];\

    }\

    free(pList);\

}\

\

- (id)initWithCoder:(NSCoder *)aDecoder\

{\

    if ([JKClass superclass] != [NSObject class]) {\

        self = [super initWithCoder:aDecoder];\

    }\

    else {\

        self = [super init];\

    }\

    unsigned int count = 0;\

    objc_property_t *pList = class_copyPropertyList([JKClass class], &count);\

    for (int i=0; i <count; i++) {\

        NSString *key= [NSString stringWithFormat:@"%s", property_getName(pList[i])];\

        [self setValue:[aDecoder decodeObjectForKey:key] forKey:key]; \

    }\

    free(pList);\

    return  self;\

}



#endif



//

//  JXTCacher.h

//  jiaoxuetong

//

//  Created by wangdan on 15/6/16.

//  Copyright (c) 2015 wangdan. All rights reserved.

//


#import <Foundation/Foundation.h>




typedef NS_ENUM(int, ArchiveType)

{

    JXTFromJSONData,

    JXTFromArchiveData

};



typedef NS_ENUM(int, CacheError)

{

    CacheErrorNoError             =  0,   //无错误

    CacheErrorCacheDataNotExist   = -1,   //取缓存时,缓存文件或数据不存在

    CacheErrorBadUnarchiveData    = -2,   //解档时,源数据错误

    CacheErrorBadArchiveData      = -3,   //归档时,输入源数据错误

    CacheErrorBadInJsonData       = -4,   //存档序列化时输入源数据错误

    CacheerrorBadOutJsonData      = -5,   //取档饭序列化时数据错误

    CacheErrorReadFileFailed      = -6,   //写文件错误

    CacheErrorWriteFileFailed     = -7    //读文件错误

};


@class JXTCacher;


typedef void (^JXTCacheObjSetBlock)(JXTCacher *cacher,CacheError error);

typedef void (^JXTCacheObjGetBlock)(JXTCacher *cacher,id obj,CacheError error);


@interface JXTCacher : NSObject

@property (nonatomic,assign) long maxSize;

@property (nonatomic,readonly) long totalSize;



/**

 * 单例模式 全局共享一个模型

 */

+(JXTCacher*)cacher;




#pragma mark - 缓存存取方法 -

/**

 * 从内存中读取数据,存在或不存在均直接返回

 *

 * @param key 缓存数据key

 *

 * @param uid 用户id

 */

-(id)objectInMemoryForKey:(NSString*)key userId:(NSString*)uid;//



/**

 * 从缓存、disk中读取数据 非阻塞方法

 *

 * @param key 缓存数据key

 *

 * @param uid 当前用户id

 *

 * @param block 取到缓存后回调

 */

-(void)objectForKey:(NSString*)key userId:(NSString*)uid achive:(JXTCacheObjGetBlock)block;



/**

 * 存储对象

 *

 * @param obj 需要存储的对象

 *

 * @param key 对象存储的key

 *

 * @param uid 用户id

 *

 * @param needArchive 是否归档 needArchive 1

 *

 * 该对象必须实现归档和解档方法

 */

-(void)setObject:(id)obj forKey:(NSString *)key userId:(NSString *)uid useArchive:(ArchiveType)needArchive;


/**

 * 缓存对象方法 非阻塞方法

 *

 * @param obj 待缓存对象 当前仅支持NSDictionary NSArray

 *

 * 且其内部无其他对象模型

 *

 * @param key 缓存关键字

 *

 * @param uid 当前用户id

 *

 * @param needArchive 是否通过archive方法缓存

 *

 * @Param block 缓存完毕回调

 */

-(void)setObject:(id)obj forKey:(NSString*)key userId:(NSString*)uid useArchive:(ArchiveType)needArchive setted:(JXTCacheObjSetBlock)block;



#pragma mark - 缓存清除方法 -

/**

 * 清除某个缓存

 *

 * @param key 缓存key

 *

 * @param uid 当前用户id

 */

-(void)clearObject:(NSString*)key userId:(NSString *)uid;


/**

 * 删除某个用户对应的缓存

 *

 * @param uid 用户id

 */

-(void)clearObject:(NSString*)uid;


/**

 * 清除所有缓存

 */

-(void)clearAllObject;



@end



//

//  JXTCacher.m

//  jiaoxuetong

//

//  Created by wangdan on 15/6/16.

//  Copyright (c) 2015 wangdan. All rights reserved.

//


#import "JXTCacher.h"

#import <CommonCrypto/CommonDigest.h>





#define JXT_SIZE_OF_KEY_KEY     @"jxtobjsizekey"

#define JXT_UID_OF_KEY_KEY      @"uidofkey"

#define JXT_ARCHIVE_TYPE_OF_KEY @"archiveTypeOfKey"


#define JXTCACHE_FOLDER_PATH    NSSearchPathForDirectoriesInDomains(NSCachesDirectory,NSUserDomainMask,YES).lastObject



@interface JXTCacher()


@property (nonatomic,strong) dispatch_queue_t ioQueue_busy;

@property (nonatomic,strong) dispatch_queue_t ioQueue_idle;


@property (nonatomic,strong) NSMutableDictionary *sizeOfKey;


@property (nonatomic,strong) NSMutableDictionary *objOfKey;//存储经常交互的数据,  通过key索引

@property (nonatomic,strong) NSMutableDictionary *statusOfKey;//存储正在被访问的key状态


@property (nonatomic,strong) NSMutableDictionary *archiveTypeOfKey;





@end



@implementation JXTCacher


@synthesize totalSize = _totalSize;


-(id)init {

    if (self = [super init]) {

        [self initQueue];

        [self initMemorySize];

        [self initDiskPath];

        [self initMemorySize];

        [self initTemperyObj];

    }

    return self;

}


+(JXTCacher *)cacher {

    static JXTCacher *cacher;

    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{

        cacher = [[JXTCacher alloc] init];

    });

    return cacher;

}



#pragma  mark - 参数初始化

-(void)initQueue {

    self.ioQueue_busy = dispatch_queue_create("com.iflytek.eclass.cache.iobusy", NULL);

    self.ioQueue_idle = dispatch_queue_create("com.iflytek.eclass.cache.ioIdle", NULL);

}


-(void)initDiskPath {

    //    if (![[NSFileManager defaultManager] fileExistsAtPath:JXTCACHE_PATH isDirectory:NULL]) {

    //        [[NSFileManager defaultManager] createDirectoryAtPath:JXTCACHE_PATH withIntermediateDirectories:YES attributes:nil error:nil];

    //    }

    

}


-(void)initMemorySize {

    NSDictionary *dic = [[NSUserDefaults standardUserDefaults] objectForKey:JXT_SIZE_OF_KEY_KEY];

    self.sizeOfKey = [[NSMutableDictionary alloc] initWithDictionary:dic];

    if (self.sizeOfKey == nil || self.sizeOfKey.allKeys.count ==0) {

        self.totalSize = 0;

        self.sizeOfKey = [[NSMutableDictionary alloc] init];

    }

    else {

        for (NSString *key in self.sizeOfKey) {

            self.totalSize += [[self.sizeOfKey objectForKey:key] longValue];

        }

    }

    

    NSDictionary *archiveDic = [[NSUserDefaults standardUserDefaults] objectForKey:JXT_ARCHIVE_TYPE_OF_KEY];

    if (archiveDic == nil) {

        self.archiveTypeOfKey = [[NSMutableDictionary alloc] init];

    }

    else {

        self.archiveTypeOfKey = [[NSMutableDictionary alloc] initWithDictionary:archiveDic];

    }

}


-(void)initTemperyObj {

    self.statusOfKey = [[NSMutableDictionary alloc] init];

    self.objOfKey = [[NSMutableDictionary alloc] init];

}



#pragma mark - 属性 getter setter

-(void)setTotalSize:(long)totalSize {

    _totalSize = totalSize;

}





#pragma mark - 字符串处理

-(NSString *)memoryKeyOfKey:(NSString *)key userId:(NSString *)uid

{

    if (!key || !uid) {

        return nil;

    }

    return [NSString stringWithFormat:@"%@|%@",key,uid];

    return  nil;//临时memory中的obect,需要通过keyuid一起索引

}


-(NSString *)md5:(NSString *)key {

    const char *str = [key UTF8String];

    if (str == NULL) {

        str = "";

    }

    unsigned char r[CC_MD5_DIGEST_LENGTH];

    CC_MD5(str, (CC_LONG)strlen(str), r);

    NSString *fileName =

    [NSString stringWithFormat:

     @"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",

     r[0], r[1], r[2], r[3], r[4], r[5], r[6],

     r[7], r[8], r[9], r[10], r[11], r[12], r[13], r[14], r[15]];

    return fileName;

}


-(NSString*)folderPath:(NSString *)uid {

    return [NSString stringWithFormat:@"%@/%@",JXTCACHE_FOLDER_PATH,uid];

}


-(NSString*)filePath:(NSString *)uid key:(NSString*)key {

    return [NSString stringWithFormat:@"%@/%@/%@",JXTCACHE_FOLDER_PATH,uid,[self md5:key]];

}



#pragma mark - 数据存储


//该函数已经被废弃了啊,但是考虑到有一些接口还在使用

//暂时还放在这里吧

-(void)setObject:(id)obj forKey:(NSString *)key userId:(NSString *)uid {

    if (!uid || !key || !obj) {

        return;

    }

    __weak typeof(self) weakSelf = self;

    dispatch_async(self.ioQueue_busy, ^{

        NSData *data = nil;

        BOOL needWriteFile = 0;

        NSString *folderPath = [self folderPath:uid];

        NSString *filePath = [self filePath:uid key:key];

        

        if ([obj isKindOfClass:[NSDictionary class]] || [obj isKindOfClass:[NSArray class]]) {

            NSData *data = [NSJSONSerialization dataWithJSONObject:obj options:kNilOptions error:nil];

            if (data == nil) {

                return ;

            }

        }

        else {

            return ;

        }

        

        NSString *keyOfUidAndKey = [self memoryKeyOfKey:key userId:uid];

        

        if (weakSelf.sizeOfKey[keyOfUidAndKey] != nil) {

            if ([weakSelf.sizeOfKey[keyOfUidAndKey] longValue] != data.length) {

                needWriteFile = YES;

                [weakSelf.objOfKey setObject:obj forKey:keyOfUidAndKey];

                weakSelf.totalSize += data.length-[weakSelf.sizeOfKey[keyOfUidAndKey] longValue];

                [weakSelf.sizeOfKey setValue:[NSNumber numberWithLong:data.length] forKey:keyOfUidAndKey];

                {

                    [weakSelf localStoreSizeOfKey:weakSelf key:JXT_SIZE_OF_KEY_KEY];

                }

            }

            else {

                needWriteFile = NO;

            }

        }

        else {

            needWriteFile = YES;

            weakSelf.totalSize += data.length;

            [weakSelf.objOfKey setObject:obj forKey:keyOfUidAndKey];

            [weakSelf.sizeOfKey setValue:[NSNumber numberWithLong:data.length] forKey:keyOfUidAndKey];

            

            {

                [weakSelf localStoreSizeOfKey:weakSelf key:JXT_SIZE_OF_KEY_KEY];

            }

        }

        

        if (needWriteFile) {

            NSFileManager *fm = [NSFileManager defaultManager];

            if (![fm fileExistsAtPath:folderPath isDirectory:NULL]) {

                [fm createDirectoryAtPath:folderPath withIntermediateDirectories:YES attributes:nil error:nil];

            }

            

            if (![fm fileExistsAtPath:filePath isDirectory:NULL]) {

                [fm createFileAtPath:filePath contents:nil attributes:nil];

            }

        }

        

        NSError *error = [[NSError alloc] init];

        BOOL writeResult=[data writeToFile:filePath options:NSDataWritingAtomic error:&error];

        if (writeResult == 0) {

            NSLog(@"error is %@",error.domain);

        }

        

    });//end of dispatch_async

}




-(void)setObject:(id)obj forKey:(NSString *)key userId:(NSString *)uid useArchive:(ArchiveType)needArchive

{

    if (!uid || !key || !obj) {

        return;

    }

    __weak  typeof(self) weakSelf = self;

    dispatch_async(self.ioQueue_busy, ^{

        id memoryObj = nil;

        NSMutableData *data = nil;

        if (!needArchive) {

            if (![obj isKindOfClass:[NSDictionary class]] && [obj isKindOfClass:[NSArray class]]) {

                return ;

            }

            

            NSData *middleData = [NSJSONSerialization dataWithJSONObject:obj options:kNilOptions error:nil];

            if (!middleData) {

                return ;

            }

            data = [[NSMutableData alloc] initWithData:middleData];

            memoryObj = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];

        }

        else {

            NSData* middleData = [NSKeyedArchiver archivedDataWithRootObject:obj];

            if (!middleData) {

                return;

            }

            data = [[NSMutableData alloc] initWithData:middleData];

            memoryObj = [NSKeyedUnarchiver unarchiveObjectWithData:data];

        }

        

        NSString *keyOfUidAndKey = [self memoryKeyOfKey:key userId:uid];

        BOOL needWriteFile = 0;

        NSString *folderPath = [self folderPath:uid];

        NSString *filePath = [self filePath:uid key:key];

        [self.archiveTypeOfKey setObject:[NSNumber numberWithInt:needArchive] forKey:keyOfUidAndKey];

        [self localStoreArchiveTypeOfKey:self key:JXT_ARCHIVE_TYPE_OF_KEY];

        

        if (weakSelf.sizeOfKey[keyOfUidAndKey] != nil) {

            if ([weakSelf.sizeOfKey[keyOfUidAndKey] longValue] != data.length) {

                needWriteFile = YES;

                [weakSelf.objOfKey setObject:memoryObj forKey:keyOfUidAndKey];

                weakSelf.totalSize += data.length-[weakSelf.sizeOfKey[keyOfUidAndKey] longValue];

                [weakSelf.sizeOfKey setValue:[NSNumber numberWithLong:data.length] forKey:keyOfUidAndKey];

                {

                    [weakSelf localStoreSizeOfKey:weakSelf key:JXT_SIZE_OF_KEY_KEY];

                }

            }

            else {

                needWriteFile = NO;

            }

        }

        else {

            needWriteFile = YES;

            weakSelf.totalSize += data.length;

            [weakSelf.objOfKey setObject:memoryObj forKey:keyOfUidAndKey];

            [weakSelf.sizeOfKey setValue:[NSNumber numberWithLong:data.length] forKey:keyOfUidAndKey];

            

            {

                [weakSelf localStoreSizeOfKey:weakSelf key:JXT_SIZE_OF_KEY_KEY];

            }

        }

        

        if (needWriteFile) {

            NSFileManager *fm = [NSFileManager defaultManager];

            if (![fm fileExistsAtPath:folderPath isDirectory:NULL]) {

                [fm createDirectoryAtPath:folderPath withIntermediateDirectories:YES attributes:nil error:nil];

            }

            

            if (![fm fileExistsAtPath:filePath isDirectory:NULL]) {

                [fm createFileAtPath:filePath contents:nil attributes:nil];

            }

        }

        

        NSError *error = [[NSError alloc] init];

        BOOL writeResult=[data writeToFile:filePath options:NSDataWritingAtomic error:&error];

        if (writeResult == 0) {

        }

        

    });//end of dispatch_async

}




-(void)setObject:(id)obj forKey:(NSString*)key userId:(NSString*)uid useArchive:(ArchiveType)needArchive setted:(JXTCacheObjSetBlock)block

{

    if (!uid || !key || !obj) {

        return;

    }

    __weak  typeof(self) weakSelf = self;

    dispatch_async(self.ioQueue_busy, ^{

        id memoryObj = nil;

        NSMutableData *data = nil;

        if (!needArchive) {

            if (![obj isKindOfClass:[NSDictionary class]] && [obj isKindOfClass:[NSArray class]]) {

                if (block) {

                    block(weakSelf,CacheErrorBadInJsonData);

                }

                return ;

            };

            NSData *middleData = [NSJSONSerialization dataWithJSONObject:obj options:kNilOptions error:nil];

            if (!middleData) {

                if (block) {

                    block(weakSelf,CacheErrorBadInJsonData) ;

                }

                return ;

            }

            data = [[NSMutableData alloc] initWithData:middleData];

            memoryObj = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];

        }

        else {

            NSData* middleData = [NSKeyedArchiver archivedDataWithRootObject:obj];

            if (!middleData) {

                if (block) {

                    block(weakSelf,CacheErrorBadArchiveData) ;

                }

                return;

            }

            data = [[NSMutableData alloc] initWithData:middleData];

            memoryObj = [NSKeyedUnarchiver unarchiveObjectWithData:data];

        }

        

        NSString *keyOfUidAndKey = [self memoryKeyOfKey:key userId:uid];

        BOOL needWriteFile = 0;

        NSString *folderPath = [self folderPath:uid];

        NSString *filePath = [self filePath:uid key:key];

        [self.archiveTypeOfKey setObject:[NSNumber numberWithInt:needArchive] forKey:keyOfUidAndKey];

        [self localStoreArchiveTypeOfKey:self key:JXT_ARCHIVE_TYPE_OF_KEY];

        

        if (weakSelf.sizeOfKey[keyOfUidAndKey] != nil) {

            if ([weakSelf.sizeOfKey[keyOfUidAndKey] longValue] != data.length) {

                needWriteFile = YES;

                [weakSelf.objOfKey setObject:memoryObj forKey:keyOfUidAndKey];

                weakSelf.totalSize += data.length-[weakSelf.sizeOfKey[keyOfUidAndKey] longValue];

                [weakSelf.sizeOfKey setValue:[NSNumber numberWithLong:data.length] forKey:keyOfUidAndKey];

                {

                    [weakSelf localStoreSizeOfKey:weakSelf key:JXT_SIZE_OF_KEY_KEY];

                }

            }

            else {

                needWriteFile = NO;

            }

        }

        else {

            needWriteFile = YES;

            weakSelf.totalSize += data.length;

            [weakSelf.objOfKey setObject:memoryObj forKey:keyOfUidAndKey];

            [weakSelf.sizeOfKey setValue:[NSNumber numberWithLong:data.length] forKey:keyOfUidAndKey];

            

            {

                [weakSelf localStoreSizeOfKey:weakSelf key:JXT_SIZE_OF_KEY_KEY];

            }

        }

        

        if (needWriteFile) {

            NSFileManager *fm = [NSFileManager defaultManager];

            if (![fm fileExistsAtPath:folderPath isDirectory:NULL]) {

                [fm createDirectoryAtPath:folderPath withIntermediateDirectories:YES attributes:nil error:nil];

            }

            

            if (![fm fileExistsAtPath:filePath isDirectory:NULL]) {

                [fm createFileAtPath:filePath contents:nil attributes:nil];

            }

        }

        

        NSError *error = [[NSError alloc] init];

        BOOL writeResult=[data writeToFile:filePath options:NSDataWritingAtomic error:&error];

        if (writeResult == 0) {

            if (block) {

                block(weakSelf,CacheErrorWriteFileFailed);

            }

        }

        if (block) {

            block(weakSelf,CacheErrorNoError);

        }

        

    });//end of dispatch_async

}



-(id)objectInMemoryForKey:(NSString *)key userId:(NSString *)uid {

    if (!uid || !key) {

        return nil;

    }

    NSString *keyOfUidAndKey = [self memoryKeyOfKey:key userId:uid];

    if (self.objOfKey[keyOfUidAndKey] != nil) {

        return [self.objOfKey objectForKey:keyOfUidAndKey];

    }

    return nil;

}



-(void)objectForKey:(NSString *)key userId:(NSString *)uid achive:(JXTCacheObjGetBlock)block {

    

    if (!uid || !key || !block) {

        return;

    }

    __weak typeof(self) weakSelf = self;

    

    dispatch_async(self.ioQueue_busy, ^{

        NSString *keyOfUidAndKey = [weakSelf memoryKeyOfKey:key userId:uid];

        if (weakSelf.objOfKey[keyOfUidAndKey] != nil) {

            block(weakSelf,weakSelf.objOfKey[keyOfUidAndKey],CacheErrorNoError);

            return;

        }

        

        NSString *filePath = [weakSelf filePath:uid key:key];

        NSData *objData = [NSData dataWithContentsOfFile:filePath];

        

        if (objData == nil) {

            block(weakSelf,nil,CacheErrorCacheDataNotExist);

            return;

        }

        

        id obj = nil;

        BOOL archiveType = [[weakSelf.archiveTypeOfKey objectForKey:keyOfUidAndKey] intValue];

        

        if (archiveType == JXTFromJSONData) {

            @try {

                obj = [NSJSONSerialization JSONObjectWithData:objData options:kNilOptions error:nil];

            }

            @catch (NSException *exception) {

                [weakSelf clearObject:key userId:uid];

                NSLog(@"got exception when unarchive %@",exception);

                if (obj == nil) {

                    block(weakSelf,nil,CacheErrorBadUnarchiveData);

                    return ;

                }

            }

            @finally {

            }

        }

        else {

            

            @try {

                obj = [NSKeyedUnarchiver unarchiveObjectWithData:objData];

            }

            @catch (NSException *exception) {

                [weakSelf clearObject:key userId:uid];

                NSLog(@"got exception when unarchive %@",exception);

                if (obj == nil) {

                    block(weakSelf,nil,CacheErrorBadUnarchiveData);

                    return ;

                }

            }

            @finally {

            }

            

        }

        if (weakSelf.objOfKey[keyOfUidAndKey] == nil) {

            weakSelf.objOfKey[keyOfUidAndKey] = obj;

        }

        

        if (objData.length != [weakSelf.sizeOfKey[keyOfUidAndKey] longValue]) {

            [weakSelf.objOfKey setObject:obj forKey:keyOfUidAndKey];

            long oldLength = [weakSelf.sizeOfKey[keyOfUidAndKey] longValue];

            weakSelf.totalSize = weakSelf.totalSize-oldLength+objData.length;

            [weakSelf.sizeOfKey setValue:[NSNumber numberWithLong:objData.length] forKey:keyOfUidAndKey];

            {

                [weakSelf localStoreSizeOfKey:weakSelf key:JXT_SIZE_OF_KEY_KEY];

            }

        }

        block(weakSelf,obj,CacheErrorNoError);

    });

    

}


-(void)clearObject:(NSString *)key userId:(NSString *)uid {

    if (!key || !uid) {

        return;

    }

    NSString *keyOfUidAndKey = [self memoryKeyOfKey:key userId:uid];

    __weak typeof(self) weakSelf = self;

    dispatch_async(self.ioQueue_busy, ^{

        

        NSString *filePath = [weakSelf filePath:uid key:key];

        NSFileManager *fm = [NSFileManager defaultManager];

        

        if ([fm removeItemAtPath:filePath error:nil]) {

            long objSize = [weakSelf.sizeOfKey[keyOfUidAndKey] longValue];

            weakSelf.totalSize -= objSize;

            [weakSelf.sizeOfKey removeObjectForKey:keyOfUidAndKey];

            [weakSelf.objOfKey removeObjectForKey:keyOfUidAndKey];

            [weakSelf.archiveTypeOfKey removeObjectForKey:keyOfUidAndKey];

        }

        

        {

            [weakSelf localStoreSizeOfKey:weakSelf key:JXT_SIZE_OF_KEY_KEY];

            [weakSelf localStoreArchiveTypeOfKey:weakSelf key:JXT_ARCHIVE_TYPE_OF_KEY];

        }

    });

}



-(void)clearObject:(NSString*)uid {

    if (!uid) {

        return;

    }

    __weak typeof(self) weakSelf = self;

    dispatch_async(self.ioQueue_busy, ^{

        NSLog(@"删除某一个账号的id");

        

        for (NSString *totalKey in weakSelf.sizeOfKey.allKeys) {

            NSArray *keyArray = [totalKey componentsSeparatedByString:@"|"];

            NSString *arrayUid = keyArray[1];

            NSString *arrayKey = keyArray[0];

            

            if (arrayUid == uid) {

                NSFileManager *fm = [NSFileManager defaultManager];

                NSString *filePath = [weakSelf filePath:arrayUid key:arrayKey];

                if ([fm removeItemAtPath:filePath error:nil]) {

                    long objSize = [weakSelf.sizeOfKey[totalKey] longValue];

                    weakSelf.totalSize -= objSize;

                    [weakSelf.sizeOfKey removeObjectForKey:totalKey];

                    [weakSelf.objOfKey removeObjectForKey:totalKey];

                    [weakSelf.archiveTypeOfKey removeObjectForKey:totalKey];

                }

            }

        }

        [weakSelf localStoreArchiveTypeOfKey:weakSelf key:JXT_ARCHIVE_TYPE_OF_KEY];

        [weakSelf localStoreSizeOfKey:weakSelf key:JXT_SIZE_OF_KEY_KEY];

    });

}



-(void)clearAllObject {

    __weak typeof(self) weakSelf = self;

    dispatch_async(self.ioQueue_busy, ^{

        NSFileManager *fm = [NSFileManager defaultManager];

        for (NSString *key in weakSelf.sizeOfKey.allKeys) {

            NSArray *uidKeyArray = [key componentsSeparatedByString:@"|"];

            NSString *uid = uidKeyArray[1];

            NSString *fileKey = uidKeyArray[0];

            NSString *filePath = [weakSelf filePath:uid key:fileKey];

            if ([fm removeItemAtPath:filePath error:nil]) {

                long objSize = [weakSelf.sizeOfKey[key] longValue];

                weakSelf.totalSize -= objSize;

                [weakSelf.sizeOfKey removeObjectForKey:key];

                [weakSelf.objOfKey removeObjectForKey:key];

                [weakSelf.archiveTypeOfKey removeObjectForKey:key];

            }

        }

        {

            [weakSelf localStoreSizeOfKey:weakSelf key:JXT_SIZE_OF_KEY_KEY];

            [weakSelf localStoreArchiveTypeOfKey:weakSelf key:JXT_ARCHIVE_TYPE_OF_KEY];

        }

    });

}



-(void)localStoreSizeOfKey:(id)owner key:(NSString*)key {

    __weak JXTCacher* weakOwner = owner;

    [[NSUserDefaults standardUserDefaults] setObject:weakOwner.sizeOfKey forKey:key];

}



-(void)localStoreArchiveTypeOfKey:(id)owner key:(NSString*)key {

    __weak JXTCacher* weakOwner = owner;

    [[NSUserDefaults standardUserDefaults] setObject:weakOwner.archiveTypeOfKey forKey:key];

}


#pragma mark -销毁对象

-(void)dealloc {

    

}




@end

//

//  NSObject+JKCoding.h

//  runtimeProject

//

//  Created by wangdan on 15/6/20.

//  Copyright (c) 2015 wangdan. All rights reserved.

//


#import <Foundation/Foundation.h>

#import <objc/runtime.h>


@interface NSObject (JKCoding)



/**

 * 可以代替手写归档协议方法,支持

 * 继承类,对象嵌套以及字典、数组中持有对象

 *

 */

-(void)encodeWithCoder:(NSCoder *)aCoder;


-(id)initWithCoder:(NSCoder *)aDecoder;



/**

 * 用于从字典生成模型类对象

 *

 */

+(id)objectFromDic:(NSDictionary*)dic;



+(NSArray *)objectArrayFromArray:(NSArray *)array;




@end

//

//  NSObject+JKCoding.m

//  runtimeProject

//

//  Created by wangdan on 15/6/20.

//  Copyright (c) 2015 wangdan. All rights reserved.

//


#import "NSObject+JKCoding.h"


@implementation NSObject (JKCoding)



-(void)encodeWithCoder:(NSCoder *)aCoder

{

    Class currentClass = self.class;

    if (currentClass == NSObject.class) {

        return;

    }

    while (currentClass && currentClass != [NSObject class])

    {

        unsigned int count = 0;

        objc_property_t *pList = class_copyPropertyList(currentClass, &count);

        if (count>0) {

            for (int i=0;i<count;i++) {

                NSString *key = [NSString stringWithUTF8String:property_getName(pList[i])];

                [aCoder encodeObject: [self valueForKey:key] forKey:key];

            }

        }

        currentClass = class_getSuperclass(currentClass);

        free(pList);

    }

}



-(id)initWithCoder:(NSCoder *)aDecoder

{

    Class currentClass = self.class;

    if (currentClass == NSObject.class) {

        return nil;

    }

    while (currentClass && currentClass != [NSObject class])

    {

        unsigned int count = 0;

        objc_property_t *pList = class_copyPropertyList(currentClass, &count);

        if (count > 0) {

            for (int i = 0;i < count;i++) {

                NSString *key = [NSString stringWithUTF8String:property_getName(pList[i])];

                [self setValue:[aDecoder  decodeObjectForKey:key] forKey:key];

            }

        }

        currentClass = class_getSuperclass(currentClass);

        free(pList);

    }

    return  self;

}




+(id)objectFromDic:(NSDictionary*)dic

{

    return [[self alloc] initFromDic:dic];

}


+(NSArray *)objectArrayFromArray:(NSArray *)array

{

    if (array == nil || array.count == 0) {

        return nil;

    }

    

    NSMutableArray *objArray = [[NSMutableArray alloc] init ];

    [objArray enumerateObjectsUsingBlock:^(id objDic, NSUInteger idx, BOOL *stop) {

        id obj = [[self alloc] initFromDic:objDic];

        if (obj) {

            [objArray addObject:obj];

        }

    }];

    return objArray;

}


/*

 -(id)initFromDic:(NSDictionary *)dic

 {

 if (self.class != [NSObject class]) {

 self = [[self.class alloc] init];

 }

 else {

 self = [self init];

 }

 

 if (self) {

 Class currentClass = self.class;

 NSMutableArray *propertyList = [[NSMutableArray alloc] init];

 NSMutableArray *attributeNameList = [[NSMutableArray alloc] init];

 

 while (currentClass && currentClass != NSObject.class) {

 unsigned int count = 0;

 objc_property_t *pList =  class_copyPropertyList(currentClass, &count);

 if (count>0) {

 for (int i=0; i<count; i++) {

 NSString *propertyString = [NSString stringWithUTF8String:property_getName(pList[i])];

 [propertyList addObject:propertyString];

 NSString *attributeString = [NSString stringWithUTF8String:property_getAttributes(pList[i])];

 [attributeNameList addObject:attributeString];

 }

 }

 free(pList);

 currentClass = class_getSuperclass(currentClass);

 }

 

 

 if (propertyList.count == 0) {

 return self;

 }

 

 

 for (int i=0; i<propertyList.count ; i++) {

 NSString *key = propertyList[i];

 NSString *propertyType = [self getClassNameFromPropertyName:attributeNameList[i]];

 id obj = [dic objectForKey:key];

 if (!obj) {

 continue;

 }

 

 if (propertyType ==nil) {

 [self setValue:obj forKey:key];

 }

 //            else if ([propertyType isEqualToString:@"NSMutableArray"] || [propertyType isEqualToString:@"NSArray"]) {

 else if (NSClassFromString(propertyType) == [NSArray class] || NSClassFromString(propertyType) == [NSMutableArray class]) {

 

 if ([obj isKindOfClass:[NSArray class]]) {

 NSMutableArray *objArray = [[NSMutableArray alloc] init];

 SEL method = NSSelectorFromString(@"classNameForKeys");

 

 if ([self respondsToSelector:method]) {

 IMP imp = [self methodForSelector:method];

 id (*func)(id, SEL) = (void *)imp;

 Class keyClass = [func(self,method) objectForKey:key];

 SEL objMethod = NSSelectorFromString(@"objectFromDic:");

 IMP objImp = [keyClass methodForSelector:objMethod];

 id (*objFunc)(id, SEL,id) = (void *)objImp;

 if (keyClass && objImp) {

 for (NSDictionary *dic in obj) {

 id transferedObj = objFunc(keyClass,objMethod,dic);

 if (transferedObj) {

 [objArray addObject:transferedObj];

 }

 }

 [self setValue:objArray forKey:key];

 }

 }

 }

 }

 else {

 Class keyClass = NSClassFromString(propertyType);

 if (keyClass) {

 SEL method = NSSelectorFromString(@"objectFromDic:");

 IMP imp = [keyClass methodForSelector:method];

 id (*func)(id, SEL,id) = (void *)imp;

 if (imp) {

 id transferedObj = func(keyClass,method,obj);

 if (transferedObj) {

 [self setValue:transferedObj forKey:key];

 }

 }

 }

 }

 }

 }

 return self;

 }

 */


-(id)initFromDic:(NSDictionary *)dic

{

    if (self.class == NSObject.class) {

        return nil;

    }

    else {

        self = [self init];

    }

    

    if (self) {

        Class currentClass = self.class;

        NSMutableArray *propertyList = [[NSMutableArray alloc] init];

        NSMutableArray *attributeNameList = [[NSMutableArray alloc] init];

        

        while (currentClass && currentClass != NSObject.class)

        {

            unsigned int count = 0;

            objc_property_t *pList =  class_copyPropertyList(currentClass, &count);

            if (count > 0)

            {

                for (int i = 0; i < count; i++)

                {

                    NSString *propertyString = [NSString stringWithUTF8String:property_getName(pList[i])];

                    [propertyList addObject:propertyString];

                    

                    NSString *attributeString = [NSString stringWithUTF8String:property_getAttributes(pList[i])];

                    [attributeNameList addObject:attributeString];

                }

            }

            free(pList);

            currentClass = class_getSuperclass(currentClass);

        }

        

        

        if (propertyList.count == 0) {

            return self;

        }

        

        

        for (int i=0; i<propertyList.count ; i++) {

            

            NSString *key = propertyList[i];

            NSString *propertyType = [self getClassNameFromPropertyName:attributeNameList[i]];

            

            id obj = [dic objectForKey:key];

            if (obj == nil) {

                continue;

            }

            

            if (propertyType == nil) {

                [self setValue:obj forKey:key];

            }

            else if (([propertyType isEqualToString:@"NSMutableArray"] || [propertyType isEqualToString:@"NSArray"])

                     && [obj isKindOfClass:[NSArray class]]) {

                

                    SEL classNameMethod = NSSelectorFromString(@"classNameForKeys");

                    if ([self respondsToSelector:classNameMethod]) {

                        

#pragma clang diagnostic push

#pragma clang diagnostic ignored "-Warc-performSelector-leaks"

                        

                        NSDictionary *classNameDic = (NSDictionary*)[self performSelector:classNameMethod];

                        Class propertyClass = [classNameDic objectForKey:key];

                        

                        if (propertyClass) {

                            NSMutableArray *objArray = [[NSMutableArray alloc] init];

                            for (NSDictionary *objDic in obj) {

                                id transferedObj = [propertyClass objectFromDic:objDic];

                                if (transferedObj) {

                                    [objArray addObject:transferedObj];

                                }

                            }

                            [self setValue:objArray forKey:key];

                        }

                        else {

                            [self setValue:obj forKey:key];

                        }

                    }

                    else {

                        [self setValue:obj forKey:key];

                    }

            }

            else {

                

                Class keyClass = NSClassFromString(propertyType);

                if (keyClass) {

                    id transferedObj = [keyClass objectFromDic:obj];

                    if (transferedObj) {

                        [self setValue:transferedObj forKey:key];

                    }

                }

            }

        }

    }

    return self;

}




-(NSString *)getClassNameFromPropertyName:(NSString*)name

{

    if (name == nil) {

        return nil;

    }

    

    NSString * className = nil;

    if ([[name substringWithRange:NSMakeRange(1, 1)] isEqualToString:@"@"]) {

        NSString *subRangeString = [name substringWithRange:NSMakeRange(3, 3)];

        if ([subRangeString isEqualToString:@"NSA"] || [subRangeString isEqualToString:@"NSM"]) {

            className = @"NSArray";

        }

        else {

            NSString *otherSystemString = [name substringWithRange: NSMakeRange(3, 2)];

            if ([otherSystemString isEqualToString:@"NS"]) {

                className = nil;

            }

            else {

                className = [[name componentsSeparatedByString:@"\""] objectAtIndex:1];

            }

        }

    }

    return className;

}




-(NSArray *)nomalObjTypeArray

{

    NSArray *array = @[@"NSDictonary",@"NSMutalbeDictionary",@"NSString",

                       @"NSNumber",@"NSAttributeString",@"NSValue",@"NSArray",@"NSMutableArray",

                       @"NSData"];

    return array;

}



@end




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值