首页 > 代码库 > 使用FastCoder写缓存单例

使用FastCoder写缓存单例

使用FastCoder写缓存单例

FastCoder可以存储字典,数组,鄙人将FastCoder封装,CoreData可以缓存的东西,用这个都可以缓存,但是只适合缓存少量的数据(不适合存储几万条数据)。

基于文件的类请参考上一章节内容

使用详情:

源码:

使用的缓存文件

SharedFile.h 与 SharedFile.m

////  SharedFile.h//  Array////  Created by YouXianMing on 14/12/1.//  Copyright (c) 2014年 YouXianMing. All rights reserved.//#import <Foundation/Foundation.h>@interface SharedFile : NSObject/** *  存储数组 * *  @return YES,成功,NO,失败 */+ (BOOL)storeArray;/** *  返回原始的可以修改的数组 * *  @return 原始可以修改的数组 */+ (NSMutableArray *)sharedOriginalArray;/** *  返回原始数组的拷贝 * *  @return 原始数组的拷贝 */+ (NSMutableArray *)sharedCopiedArray;@end
////  SharedFile.m//  Array////  Created by YouXianMing on 14/12/1.//  Copyright (c) 2014年 YouXianMing. All rights reserved.//#import "SharedFile.h"#import "NSString+File.h"#import "NSObject+FastCoder.h"static NSString *filePath = @"/Library/Caches/YouXianMing";NSMutableArray *storedArray = nil;@implementation SharedFile+ (void)initialize {    if (self == [SharedFile class]) {                if ([filePath exist] == NO) {            storedArray = [NSMutableArray array];        } else {            storedArray = [@"SharedFile" useFastCoderToRecoverFromFilePath:[filePath path]];        }    }}+ (BOOL)storeArray {    return [storedArray useFastCoderToWriteToFilePath:[filePath path]];}+ (NSMutableArray *)sharedOriginalArray {    return storedArray;}+ (NSMutableArray *)sharedCopiedArray {    return [NSMutableArray arrayWithArray:storedArray];}@end

FastCoder.h 与 FastCoder.m

////  FastCoding.h////  Version 3.0.2////  Created by Nick Lockwood on 09/12/2013.//  Copyright (c) 2013 Charcoal Design////  Distributed under the permissive zlib License//  Get the latest version from here:////  https://github.com/nicklockwood/FastCoding////  This software is provided ‘as-is‘, without any express or implied//  warranty.  In no event will the authors be held liable for any damages//  arising from the use of this software.////  Permission is granted to anyone to use this software for any purpose,//  including commercial applications, and to alter it and redistribute it//  freely, subject to the following restrictions:////  1. The origin of this software must not be misrepresented; you must not//  claim that you wrote the original software. If you use this software//  in a product, an acknowledgment in the product documentation would be//  appreciated but is not required.////  2. Altered source versions must be plainly marked as such, and must not be//  misrepresented as being the original software.////  3. This notice may not be removed or altered from any source distribution.//#import <Foundation/Foundation.h>extern NSString *const FastCodingException;@interface NSObject (FastCoding)+ (NSArray *)fastCodingKeys;- (id)awakeAfterFastCoding;- (Class)classForFastCoding;- (BOOL)preferFastCoding;@end@interface FastCoder : NSObject+ (id)objectWithData:(NSData *)data;+ (id)propertyListWithData:(NSData *)data;+ (NSData *)dataWithRootObject:(id)object;@end
////  FastCoding.m////  Version 3.0.2////  Created by Nick Lockwood on 09/12/2013.//  Copyright (c) 2013 Charcoal Design////  Distributed under the permissive zlib License//  Get the latest version from here:////  https://github.com/nicklockwood/FastCoding////  This software is provided ‘as-is‘, without any express or implied//  warranty.  In no event will the authors be held liable for any damages//  arising from the use of this software.////  Permission is granted to anyone to use this software for any purpose,//  including commercial applications, and to alter it and redistribute it//  freely, subject to the following restrictions:////  1. The origin of this software must not be misrepresented; you must not//  claim that you wrote the original software. If you use this software//  in a product, an acknowledgment in the product documentation would be//  appreciated but is not required.////  2. Altered source versions must be plainly marked as such, and must not be//  misrepresented as being the original software.////  3. This notice may not be removed or altered from any source distribution.//#import "FastCoder.h"#import <objc/runtime.h>#import <CoreGraphics/CoreGraphics.h>#import <Availability.h>#if __has_feature(objc_arc)#pragma clang diagnostic ignored "-Wpedantic"#warning FastCoding runs slower under ARC. It is recommended that you disable it for this file#endif#pragma clang diagnostic ignored "-Wgnu"#pragma clang diagnostic ignored "-Wpointer-arith"#pragma clang diagnostic ignored "-Wmissing-prototypes"#pragma clang diagnostic ignored "-Wfour-char-constants"#pragma clang diagnostic ignored "-Wobjc-missing-property-synthesis"#pragma clang diagnostic ignored "-Wdirect-ivar-access"NSString *const FastCodingException = @"FastCodingException";static const uint32_t FCIdentifier = FAST;static const uint16_t FCMajorVersion = 3;static const uint16_t FCMinorVersion = 0;typedef struct{    uint32_t identifier;    uint16_t majorVersion;    uint16_t minorVersion;}FCHeader;typedef NS_ENUM(uint8_t, FCType){    FCTypeNil = 0,    FCTypeNull,    FCTypeObjectAlias8,    FCTypeObjectAlias16,    FCTypeObjectAlias32,    FCTypeStringAlias8,    FCTypeStringAlias16,    FCTypeStringAlias32,    FCTypeString,    FCTypeDictionary,    FCTypeArray,    FCTypeSet,    FCTypeOrderedSet,    FCTypeTrue,    FCTypeFalse,    FCTypeInt8,    FCTypeInt16,    FCTypeInt32,    FCTypeInt64,    FCTypeFloat32,    FCTypeFloat64,    FCTypeData,    FCTypeDate,    FCTypeMutableString,    FCTypeMutableDictionary,    FCTypeMutableArray,    FCTypeMutableSet,    FCTypeMutableOrderedSet,    FCTypeMutableData,    FCTypeClassDefinition,    FCTypeObject8,    FCTypeObject16,    FCTypeObject32,    FCTypeURL,    FCTypePoint,    FCTypeSize,    FCTypeRect,    FCTypeRange,    FCTypeVector,    FCTypeAffineTransform,    FCType3DTransform,    FCTypeMutableIndexSet,    FCTypeIndexSet,    FCTypeNSCodedObject,      FCTypeCount // sentinel value};#if !__has_feature(objc_arc)#define FC_AUTORELEASE(x) [(x) autorelease]#else#define FC_AUTORELEASE(x) (x)#endif#import <TargetConditionals.h>#if TARGET_OS_IPHONE#define OR_IF_MAC(x)#else#define OR_IF_MAC(x) || (x)#endif#define FC_ASSERT_FITS(length, offset, total) { if ((NSUInteger)((offset) + (length)) > (total)) \[NSException raise:FastCodingException format:@"Unexpected EOF when parsing object starting at %i", (int32_t)(offset)]; }#define FC_READ_VALUE(type, offset, input, total) type value; { \FC_ASSERT_FITS (sizeof(type), offset, total); value = *(type *)(input + offset); offset += sizeof(value); }#define FC_ALIGN_INPUT(type, offset) { \unsigned long align = offset % sizeof(type); if (align) offset += sizeof(type) - align; }#define FC_ALIGN_OUTPUT(type, output) { \unsigned long align = [output length] % sizeof(type); if (align) [output increaseLengthBy:sizeof(type) - align]; }@interface FCNSCoder : NSCoder@end@interface FCNSCoder (){    @public    __unsafe_unretained id _rootObject;    __unsafe_unretained NSMutableData *_output;    __unsafe_unretained NSMutableDictionary *_objectCache;    __unsafe_unretained NSMutableDictionary *_classCache;    __unsafe_unretained NSMutableDictionary *_stringCache;    __unsafe_unretained NSMutableDictionary *_classesByName;}@end@interface FCNSDecoder : NSCoder@endtypedef id FCTypeConstructor(FCNSDecoder *);@interface FCNSDecoder (){    @public    NSUInteger *_offset;    const void *_input;    NSUInteger _total;    FCTypeConstructor **_constructors;    __unsafe_unretained NSData *_objectCache;    __unsafe_unretained NSData *_classCache;    __unsafe_unretained NSData *_stringCache;    __unsafe_unretained NSMutableArray *_propertyDictionaryPool;    __unsafe_unretained NSMutableDictionary *_properties;}@end@interface FCClassDefinition : NSObject@end@interface FCClassDefinition (){@public    __unsafe_unretained NSString *_className;    __unsafe_unretained NSArray *_propertyKeys;}@end@interface NSObject (FastCoding_Private)- (void)FC_encodeWithCoder:(__unsafe_unretained FCNSCoder *)coder;@endstatic inline NSUInteger FCCacheReadObject(__unsafe_unretained id object, __unsafe_unretained NSData *cache){    NSUInteger offset = (NSUInteger)CFDataGetLength((__bridge CFMutableDataRef)cache);    CFDataAppendBytes((__bridge CFMutableDataRef)cache, (void *)&object, sizeof(id));    return offset;}static inline void FCReplaceCachedObject(NSUInteger index, __unsafe_unretained id object, __unsafe_unretained NSData *cache){    CFDataReplaceBytes((__bridge CFMutableDataRef)cache, CFRangeMake((CFIndex)index, sizeof(id)), (void *)&object, sizeof(id));}static inline id FCCachedObjectAtIndex(NSUInteger index, __unsafe_unretained NSData *cache){    return ((__unsafe_unretained id *)(void *)CFDataGetBytePtr((__bridge CFMutableDataRef)cache))[index];}static id FCReadObject(__unsafe_unretained FCNSDecoder *decoder);static id FCReadObject_2_3(__unsafe_unretained FCNSDecoder *decoder);static inline uint8_t FCReadType(__unsafe_unretained FCNSDecoder *decoder){    FC_READ_VALUE(uint8_t, *decoder->_offset, decoder->_input, decoder->_total);    return value;}static inline uint8_t FCReadRawUInt8(__unsafe_unretained FCNSDecoder *decoder){    FC_READ_VALUE(uint8_t, *decoder->_offset, decoder->_input, decoder->_total);    return value;}static inline uint16_t FCReadRawUInt16(__unsafe_unretained FCNSDecoder *decoder){    FC_READ_VALUE(uint16_t, *decoder->_offset, decoder->_input, decoder->_total);    return value;}static inline uint32_t FCReadRawUInt32(__unsafe_unretained FCNSDecoder *decoder){    FC_READ_VALUE(uint32_t, *decoder->_offset, decoder->_input, decoder->_total);    return value;}static inline double FCReadRawDouble(__unsafe_unretained FCNSDecoder *decoder){    FC_READ_VALUE(double_t, *decoder->_offset, decoder->_input, decoder->_total);    return value;}static id FCReadRawString(__unsafe_unretained FCNSDecoder *decoder){    __autoreleasing NSString *string = nil;    NSUInteger length = strlen(decoder->_input + *decoder->_offset) + 1;    FC_ASSERT_FITS(length, *decoder->_offset, decoder->_total);    if (length > 1)    {        string = CFBridgingRelease(CFStringCreateWithBytes(NULL, decoder->_input + *decoder->_offset,                                                           (CFIndex)length - 1, kCFStringEncodingUTF8, false));    }    else    {        string = @"";    }    *decoder->_offset += length;    return string;}static id FCReadNil(__unused __unsafe_unretained FCNSDecoder *decoder){    return nil;}static id FCReadNull(__unused __unsafe_unretained FCNSDecoder *decoder){    return [NSNull null];}static id FCReadAlias8(__unsafe_unretained FCNSDecoder *decoder){  FC_ALIGN_INPUT(uint8_t, *decoder->_offset);  return FCCachedObjectAtIndex(FCReadRawUInt8(decoder), decoder->_objectCache);}static id FCReadAlias16(__unsafe_unretained FCNSDecoder *decoder){    FC_ALIGN_INPUT(uint16_t, *decoder->_offset);    return FCCachedObjectAtIndex(FCReadRawUInt16(decoder), decoder->_objectCache);}static id FCReadAlias32(__unsafe_unretained FCNSDecoder *decoder){    FC_ALIGN_INPUT(uint32_t, *decoder->_offset);    return FCCachedObjectAtIndex(FCReadRawUInt32(decoder), decoder->_objectCache);}static id FCReadStringAlias8(__unsafe_unretained FCNSDecoder *decoder){    FC_ALIGN_INPUT(uint8_t, *decoder->_offset);    return FCCachedObjectAtIndex(FCReadRawUInt8(decoder), decoder->_stringCache);}static id FCReadStringAlias16(__unsafe_unretained FCNSDecoder *decoder){    FC_ALIGN_INPUT(uint16_t, *decoder->_offset);    return FCCachedObjectAtIndex(FCReadRawUInt16(decoder), decoder->_stringCache);}static id FCReadStringAlias32(__unsafe_unretained FCNSDecoder *decoder){    FC_ALIGN_INPUT(uint32_t, *decoder->_offset);    return FCCachedObjectAtIndex(FCReadRawUInt32(decoder), decoder->_stringCache);}static id FCReadString(__unsafe_unretained FCNSDecoder *decoder){    NSString *string = FCReadRawString(decoder);    FCCacheReadObject(string, decoder->_stringCache);    return string;}static id FCReadMutableString(__unsafe_unretained FCNSDecoder *decoder){    __autoreleasing NSMutableString *string = nil;    NSUInteger length = strlen(decoder->_input + *decoder->_offset) + 1;    FC_ASSERT_FITS(length, *decoder->_offset, decoder->_total);    if (length > 1)    {        string = FC_AUTORELEASE([[NSMutableString alloc] initWithBytes:decoder->_input + *decoder->_offset length:length - 1 encoding:NSUTF8StringEncoding]);    }    else    {        string = [NSMutableString string];    }    *decoder->_offset += length;    FCCacheReadObject(string, decoder->_objectCache);    return string;}static id FCReadDictionary(__unsafe_unretained FCNSDecoder *decoder){    FC_ALIGN_INPUT(uint32_t, *decoder->_offset);    uint32_t count = FCReadRawUInt32(decoder);    __autoreleasing NSDictionary *dict = nil;    if (count)    {                __autoreleasing id *keys = (__autoreleasing id *)malloc(count * sizeof(id));        __autoreleasing id *objects = (__autoreleasing id *)malloc(count * sizeof(id));        for (uint32_t i = 0; i < count; i++)        {            objects[i] = FCReadObject(decoder);            keys[i] = FCReadObject(decoder);        }                dict = [NSDictionary dictionaryWithObjects:objects forKeys:keys count:count];        free(objects);        free(keys);    }    else    {        dict = @{};    }    FCCacheReadObject(dict, decoder->_objectCache);    return dict;}static id FCReadMutableDictionary(__unsafe_unretained FCNSDecoder *decoder){    FC_ALIGN_INPUT(uint32_t, *decoder->_offset);    uint32_t count = FCReadRawUInt32(decoder);    __autoreleasing NSMutableDictionary *dict = CFBridgingRelease(CFDictionaryCreateMutable(NULL, (CFIndex)count, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));    FCCacheReadObject(dict, decoder->_objectCache);    for (uint32_t i = 0; i < count; i++)    {        __autoreleasing id object = FCReadObject(decoder);        __autoreleasing id key = FCReadObject(decoder);        CFDictionarySetValue((__bridge CFMutableDictionaryRef)dict, (__bridge const void *)key, (__bridge const void *)object);    }    return dict;}static id FCReadArray(__unsafe_unretained FCNSDecoder *decoder){    FC_ALIGN_INPUT(uint32_t, *decoder->_offset);    uint32_t count = FCReadRawUInt32(decoder);    __autoreleasing NSArray *array = nil;    if (count)    {        __autoreleasing id *objects = (__autoreleasing id *)malloc(count * sizeof(id));        for (uint32_t i = 0; i < count; i++)        {            objects[i] = FCReadObject(decoder);        }        array = [NSArray arrayWithObjects:objects count:count];        free(objects);    }    else    {        array = @[];    }    FCCacheReadObject(array, decoder->_objectCache);    return array;}static id FCReadMutableArray(__unsafe_unretained FCNSDecoder *decoder){    FC_ALIGN_INPUT(uint32_t, *decoder->_offset);    uint32_t count = FCReadRawUInt32(decoder);    __autoreleasing NSMutableArray *array = [NSMutableArray arrayWithCapacity:count];    FCCacheReadObject(array, decoder->_objectCache);    for (uint32_t i = 0; i < count; i++)    {        CFArrayAppendValue((__bridge CFMutableArrayRef)array, (__bridge void *)FCReadObject(decoder));    }    return array;}static id FCReadSet(__unsafe_unretained FCNSDecoder *decoder){    FC_ALIGN_INPUT(uint32_t, *decoder->_offset);    uint32_t count = FCReadRawUInt32(decoder);    __autoreleasing NSSet *set = nil;    if (count)    {        __autoreleasing id *objects = (__autoreleasing id *)malloc(count * sizeof(id));        for (uint32_t i = 0; i < count; i++)        {            objects[i] = FCReadObject(decoder);        }        set = [NSSet setWithObjects:objects count:count];        free(objects);    }    else    {        set = [NSSet set];    }    FCCacheReadObject(set, decoder->_objectCache);    return set;}static id FCReadMutableSet(__unsafe_unretained FCNSDecoder *decoder){    FC_ALIGN_INPUT(uint32_t, *decoder->_offset);    uint32_t count = FCReadRawUInt32(decoder);    __autoreleasing NSMutableSet *set = [NSMutableSet setWithCapacity:count];    FCCacheReadObject(set, decoder->_objectCache);    for (uint32_t i = 0; i < count; i++)    {        [set addObject:FCReadObject(decoder)];    }    return set;}static id FCReadOrderedSet(__unsafe_unretained FCNSDecoder *decoder){    FC_ALIGN_INPUT(uint32_t, *decoder->_offset);    uint32_t count = FCReadRawUInt32(decoder);    __autoreleasing NSOrderedSet *set = nil;    if (count)    {        __autoreleasing id *objects = (__autoreleasing id *)malloc(count * sizeof(id));        for (uint32_t i = 0; i < count; i++)        {            objects[i] = FCReadObject(decoder);        }        set = [NSOrderedSet orderedSetWithObjects:objects count:count];        free(objects);    }    else    {        set = [NSOrderedSet orderedSet];    }    FCCacheReadObject(set, decoder->_objectCache);    return set;}static id FCReadMutableOrderedSet(__unsafe_unretained FCNSDecoder *decoder){    FC_ALIGN_INPUT(uint32_t, *decoder->_offset);    uint32_t count = FCReadRawUInt32(decoder);    __autoreleasing NSMutableOrderedSet *set = [NSMutableOrderedSet orderedSetWithCapacity:count];    FCCacheReadObject(set, decoder->_objectCache);    for (uint32_t i = 0; i < count; i++)    {        [set addObject:FCReadObject(decoder)];    }    return set;}static id FCReadTrue(__unused __unsafe_unretained FCNSDecoder *decoder){    return @YES;}static id FCReadFalse(__unused __unsafe_unretained FCNSDecoder *decoder){    return @NO;}static id FCReadInt8(__unsafe_unretained FCNSDecoder *decoder){    FC_READ_VALUE(int8_t, *decoder->_offset, decoder->_input, decoder->_total);    __autoreleasing NSNumber *number = @(value);    return number;}static id FCReadInt16(__unsafe_unretained FCNSDecoder *decoder){    FC_ALIGN_INPUT(int16_t, *decoder->_offset);    FC_READ_VALUE(int16_t, *decoder->_offset, decoder->_input, decoder->_total);    __autoreleasing NSNumber *number = @(value);    return number;}static id FCReadInt32(__unsafe_unretained FCNSDecoder *decoder){    FC_ALIGN_INPUT(int32_t, *decoder->_offset);    FC_READ_VALUE(int32_t, *decoder->_offset, decoder->_input, decoder->_total);    __autoreleasing NSNumber *number = @(value);    return number;}static id FCReadInt64(__unsafe_unretained FCNSDecoder *decoder){    FC_ALIGN_INPUT(int64_t, *decoder->_offset);    FC_READ_VALUE(int64_t, *decoder->_offset, decoder->_input, decoder->_total);    __autoreleasing NSNumber *number = @(value);    return number;}static id FCReadFloat32(__unsafe_unretained FCNSDecoder *decoder){    FC_ALIGN_INPUT(float_t, *decoder->_offset);    FC_READ_VALUE(float_t, *decoder->_offset, decoder->_input, decoder->_total);    __autoreleasing NSNumber *number = @(value);    return number;}static id FCReadFloat64(__unsafe_unretained FCNSDecoder *decoder){    FC_ALIGN_INPUT(double_t, *decoder->_offset);    FC_READ_VALUE(double_t, *decoder->_offset, decoder->_input, decoder->_total);    __autoreleasing NSNumber *number = @(value);    return number;}static id FCReadData(__unsafe_unretained FCNSDecoder *decoder){    FC_ALIGN_INPUT(uint32_t, *decoder->_offset);    uint32_t length = FCReadRawUInt32(decoder);    NSUInteger paddedLength = length + (4 - ((length % 4) ?: 4));    FC_ASSERT_FITS(paddedLength, *decoder->_offset, decoder->_total);    __autoreleasing NSData *data = http://www.mamicode.com/[NSData dataWithBytes:(decoder->_input + *decoder->_offset) length:length];    *decoder->_offset += paddedLength;    FCCacheReadObject(data, decoder->_objectCache);    return data;}static id FCReadMutableData(__unsafe_unretained FCNSDecoder *decoder){    FC_ALIGN_INPUT(uint32_t, *decoder->_offset);    uint32_t length = FCReadRawUInt32(decoder);    NSUInteger paddedLength = length + (4 - ((length % 4) ?: 4));    FC_ASSERT_FITS(paddedLength, *decoder->_offset, decoder->_total);    __autoreleasing NSMutableData *data = http://www.mamicode.com/[NSMutableData dataWithBytes:(decoder->_input + *decoder->_offset) length:length];    *decoder->_offset += paddedLength;    FCCacheReadObject(data, decoder->_objectCache);    return data;}static id FCReadDate(__unsafe_unretained FCNSDecoder *decoder){    FC_ALIGN_INPUT(NSTimeInterval, *decoder->_offset);    FC_READ_VALUE(NSTimeInterval, *decoder->_offset, decoder->_input, decoder->_total);    __autoreleasing NSDate *date = [NSDate dateWithTimeIntervalSince1970:value];    return date;}static id FCReadClassDefinition(__unsafe_unretained FCNSDecoder *decoder){    __autoreleasing FCClassDefinition *definition = FC_AUTORELEASE([[FCClassDefinition alloc] init]);    FCCacheReadObject(definition, decoder->_classCache);    definition->_className = FCReadRawString(decoder);    FC_ALIGN_INPUT(uint32_t, *decoder->_offset);    uint32_t count = FCReadRawUInt32(decoder);    if (count)    {        __autoreleasing id *objects = (__autoreleasing id *)malloc(count * sizeof(id));        for (uint32_t i = 0; i < count; i++)        {            objects[i] = FCReadRawString(decoder);        }        __autoreleasing NSArray *propertyKeys = [NSArray arrayWithObjects:objects count:count];        definition->_propertyKeys = propertyKeys;        free(objects);    }        //now return the actual object instance    return FCReadObject(decoder);}static id FCReadObjectInstance(__unsafe_unretained FCNSDecoder *decoder, NSUInteger classIndex){    __autoreleasing FCClassDefinition *definition = FCCachedObjectAtIndex(classIndex, decoder->_classCache);    __autoreleasing Class objectClass = NSClassFromString(definition->_className);    __autoreleasing id object = nil;    if (objectClass)    {        object = FC_AUTORELEASE([[objectClass alloc] init]);    }    else if (definition->_className)    {        object = [NSMutableDictionary dictionaryWithObject:definition->_className forKey:@"$class"];    }    else if (object)    {        object = [NSMutableDictionary dictionary];    }    NSUInteger cacheIndex = FCCacheReadObject(object, decoder->_objectCache);    for (__unsafe_unretained NSString *key in definition->_propertyKeys)    {        [object setValue:FCReadObject(decoder) forKey:key];    }    id newObject = [object awakeAfterFastCoding];    if (newObject != object)    {        //TODO: this is only a partial solution, as any objects that referenced        //this object between when it was created and now will have received incorrect instance        FCReplaceCachedObject(cacheIndex, newObject, decoder->_objectCache);    }    return newObject;}static id FCReadObject8(__unsafe_unretained FCNSDecoder *decoder){    return FCReadObjectInstance(decoder, FCReadRawUInt8(decoder));}static id FCReadObject16(__unsafe_unretained FCNSDecoder *decoder){    FC_ALIGN_INPUT(uint16_t, *decoder->_offset);    return FCReadObjectInstance(decoder, FCReadRawUInt16(decoder));}static id FCReadObject32(__unsafe_unretained FCNSDecoder *decoder){    FC_ALIGN_INPUT(uint32_t, *decoder->_offset);    return FCReadObjectInstance(decoder, FCReadRawUInt32(decoder));}static id FCReadURL(__unsafe_unretained FCNSDecoder *decoder){    __autoreleasing NSURL *URL = [NSURL URLWithString:FCReadObject(decoder) relativeToURL:FCReadObject(decoder)];    FCCacheReadObject(URL, decoder->_stringCache);    return URL;}static id FCReadPoint(__unsafe_unretained FCNSDecoder *decoder){    FC_ALIGN_INPUT(double_t, *decoder->_offset);    CGPoint point = {(CGFloat)FCReadRawDouble(decoder), (CGFloat)FCReadRawDouble(decoder)};    NSValue *value = http://www.mamicode.com/[NSValue valueWithBytes:&point objCType:@encode(CGPoint)];    return value;}static id FCReadSize(__unsafe_unretained FCNSDecoder *decoder){    FC_ALIGN_INPUT(double_t, *decoder->_offset);    CGSize size = {(CGFloat)FCReadRawDouble(decoder), (CGFloat)FCReadRawDouble(decoder)};    NSValue *value = http://www.mamicode.com/[NSValue valueWithBytes:&size objCType:@encode(CGSize)];    return value;}static id FCReadRect(__unsafe_unretained FCNSDecoder *decoder){    FC_ALIGN_INPUT(double_t, *decoder->_offset);    CGRect rect =    {        {(CGFloat)FCReadRawDouble(decoder), (CGFloat)FCReadRawDouble(decoder)},        {(CGFloat)FCReadRawDouble(decoder), (CGFloat)FCReadRawDouble(decoder)}    };    NSValue *value = http://www.mamicode.com/[NSValue valueWithBytes:&rect objCType:@encode(CGRect)];    return value;}static id FCReadRange(__unsafe_unretained FCNSDecoder *decoder){    FC_ALIGN_INPUT(uint32_t, *decoder->_offset);    NSRange range = {FCReadRawUInt32(decoder), FCReadRawUInt32(decoder)};    NSValue *value = http://www.mamicode.com/[NSValue valueWithBytes:&range objCType:@encode(NSRange)];    return value;}static id FCReadVector(__unsafe_unretained FCNSDecoder *decoder){    FC_ALIGN_INPUT(double_t, *decoder->_offset);    CGVector point = {(CGFloat)FCReadRawDouble(decoder), (CGFloat)FCReadRawDouble(decoder)};    NSValue *value = http://www.mamicode.com/[NSValue valueWithBytes:&point objCType:@encode(CGVector)];    return value;}static id FCReadAffineTransform(__unsafe_unretained FCNSDecoder *decoder){    FC_ALIGN_INPUT(double_t, *decoder->_offset);    CGAffineTransform transform =    {        (CGFloat)FCReadRawDouble(decoder), (CGFloat)FCReadRawDouble(decoder),        (CGFloat)FCReadRawDouble(decoder), (CGFloat)FCReadRawDouble(decoder),        (CGFloat)FCReadRawDouble(decoder), (CGFloat)FCReadRawDouble(decoder)    };    NSValue *value = http://www.mamicode.com/[NSValue valueWithBytes:&transform objCType:@encode(CGAffineTransform)];    return value;}static id FCRead3DTransform(__unsafe_unretained FCNSDecoder *decoder){    FC_ALIGN_INPUT(double_t, *decoder->_offset);    CGFloat transform[] =    {        (CGFloat)FCReadRawDouble(decoder), (CGFloat)FCReadRawDouble(decoder),        (CGFloat)FCReadRawDouble(decoder), (CGFloat)FCReadRawDouble(decoder),        (CGFloat)FCReadRawDouble(decoder), (CGFloat)FCReadRawDouble(decoder),        (CGFloat)FCReadRawDouble(decoder), (CGFloat)FCReadRawDouble(decoder),        (CGFloat)FCReadRawDouble(decoder), (CGFloat)FCReadRawDouble(decoder),        (CGFloat)FCReadRawDouble(decoder), (CGFloat)FCReadRawDouble(decoder),        (CGFloat)FCReadRawDouble(decoder), (CGFloat)FCReadRawDouble(decoder),        (CGFloat)FCReadRawDouble(decoder), (CGFloat)FCReadRawDouble(decoder)    };    NSValue *value = http://www.mamicode.com/[NSValue valueWithBytes:&transform objCType:@encode(CGFloat[16])];    return value;}static id FCReadMutableIndexSet(__unsafe_unretained FCNSDecoder *decoder){    FC_ALIGN_INPUT(uint32_t, *decoder->_offset);    uint32_t rangeCount = FCReadRawUInt32(decoder);    __autoreleasing NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet];    FCCacheReadObject(indexSet, decoder->_objectCache);    for (uint32_t i = 0; i < rangeCount; i++)    {        NSRange range = {FCReadRawUInt32(decoder), FCReadRawUInt32(decoder)};        [indexSet addIndexesInRange:range];    }    return indexSet;}static id FCReadIndexSet(__unsafe_unretained FCNSDecoder *decoder){    FC_ALIGN_INPUT(uint32_t, *decoder->_offset);    uint32_t rangeCount = FCReadRawUInt32(decoder);    __autoreleasing NSIndexSet *indexSet;    if (rangeCount == 1)    {        //common case optimisation        NSRange range = {FCReadRawUInt32(decoder), FCReadRawUInt32(decoder)};        indexSet = [NSIndexSet indexSetWithIndexesInRange:range];    }    else    {        indexSet = [NSMutableIndexSet indexSet];        for (uint32_t i = 0; i < rangeCount; i++)        {            NSRange range = {FCReadRawUInt32(decoder), FCReadRawUInt32(decoder)};            [(NSMutableIndexSet *)indexSet addIndexesInRange:range];        }        indexSet = [indexSet copy];            }    FCCacheReadObject(indexSet, decoder->_objectCache);    return indexSet;}static id FCReadNSCodedObject(__unsafe_unretained FCNSDecoder *decoder){    NSString *className = FCReadObject(decoder);    NSMutableDictionary *oldProperties = decoder->_properties;    if ([decoder->_propertyDictionaryPool count])    {        decoder->_properties = [decoder->_propertyDictionaryPool lastObject];        [decoder->_propertyDictionaryPool removeLastObject];        [decoder->_properties removeAllObjects];    }    else    {        const CFDictionaryKeyCallBacks stringKeyCallbacks =        {            0,            NULL,            NULL,            NULL,            CFEqual,            CFHash        };              decoder->_properties = CFBridgingRelease(CFDictionaryCreateMutable(NULL, 0, &stringKeyCallbacks, NULL));    }    while (true)    {        id object = FCReadObject(decoder);        if (!object) break;        NSString *key = FCReadObject(decoder);        decoder->_properties[key] = object;    }    id object = [[NSClassFromString(className) alloc] initWithCoder:decoder];    [decoder->_propertyDictionaryPool addObject:decoder->_properties];    decoder->_properties = oldProperties;    FCCacheReadObject(object, decoder->_objectCache);    return object;}static id FCReadObject(__unsafe_unretained FCNSDecoder *decoder){    FCType type = FCReadType(decoder);    FCTypeConstructor *constructor = NULL;    if (type < FCTypeCount)    {        constructor = decoder->_constructors[type];    }    if (!constructor)    {        [NSException raise:FastCodingException format:@"FastCoding cannot decode object of type: %i", type];        return nil;    }    return constructor(decoder);}id FCParseData(NSData *data, FCTypeConstructor *constructors[]){    NSUInteger length = [data length];    if (length < sizeof(FCHeader))    {        //not a valid FastArchive        return nil;    }        //read header    FCHeader header;    const void *input = data.bytes;    memcpy(&header, input, sizeof(header));    if (header.identifier != FCIdentifier)    {        //not a FastArchive        return nil;    }    if (header.majorVersion < 2 || header.majorVersion > FCMajorVersion)    {        //not compatible        NSLog(@"This version of the FastCoding library doesn‘t support FastCoding version %i.%i files", header.majorVersion, header.minorVersion);        return nil;    }        //create decoder    NSUInteger offset = sizeof(header);    FCNSDecoder *decoder = FC_AUTORELEASE([[FCNSDecoder alloc] init]);    decoder->_constructors = constructors;    decoder->_input = input;    decoder->_offset = &offset;    decoder->_total = length;        //read data    __autoreleasing NSMutableData *objectCache = [NSMutableData dataWithCapacity:FCReadRawUInt32(decoder) * sizeof(id)];    decoder->_objectCache = objectCache;    if (header.majorVersion < 3)    {        return FCReadObject_2_3(decoder);    }    else    {        __autoreleasing NSMutableData *classCache = [NSMutableData dataWithCapacity:FCReadRawUInt32(decoder) * sizeof(id)];        __autoreleasing NSMutableData *stringCache = [NSMutableData dataWithCapacity:FCReadRawUInt32(decoder) * sizeof(id)];        __autoreleasing NSMutableArray *propertyDictionaryPool = CFBridgingRelease(CFArrayCreateMutable(NULL, 0, NULL));              decoder->_classCache = classCache;        decoder->_stringCache = stringCache;        decoder->_propertyDictionaryPool = propertyDictionaryPool;              @try        {            return FCReadObject(decoder);        }        @catch (NSException *exception)        {            NSLog(@"%@", [exception reason]);            return nil;        }    }}static inline NSUInteger FCCacheWrittenObject(__unsafe_unretained id object, __unsafe_unretained NSMutableDictionary *cache){    NSUInteger count = (NSUInteger)CFDictionaryGetCount((CFMutableDictionaryRef)cache);    CFDictionarySetValue((CFMutableDictionaryRef)cache, (__bridge const void *)(object), (const void *)(count + 1));    return count;}static inline NSUInteger FCIndexOfCachedObject(__unsafe_unretained id object, __unsafe_unretained NSMutableDictionary *cache){    const void *index = CFDictionaryGetValue((__bridge CFMutableDictionaryRef)cache, (__bridge const void *)object);    if (index)    {        return ((NSUInteger)index) - 1;    }    return NSNotFound;}static inline void FCWriteType(FCType value, __unsafe_unretained NSMutableData *output){    [output appendBytes:&value length:sizeof(value)];}static inline void FCWriteUInt8(uint8_t value, __unsafe_unretained NSMutableData *output){    [output appendBytes:&value length:sizeof(value)];}static inline void FCWriteUInt16(uint16_t value, __unsafe_unretained NSMutableData *output){    [output appendBytes:&value length:sizeof(value)];}static inline void FCWriteUInt32(uint32_t value, __unsafe_unretained NSMutableData *output){    [output appendBytes:&value length:sizeof(value)];}static inline void FCWriteDouble(double_t value, __unsafe_unretained NSMutableData *output){    [output appendBytes:&value length:sizeof(value)];}static inline void FCWriteString(__unsafe_unretained NSString *string, __unsafe_unretained NSMutableData *output){    const char *utf8 = [string UTF8String];    NSUInteger length = strlen(utf8) + 1;    [output appendBytes:utf8 length:length];}static inline BOOL FCWriteObjectAlias(__unsafe_unretained id object, __unsafe_unretained FCNSCoder *coder){    NSUInteger index = FCIndexOfCachedObject(object, coder->_objectCache);    if (index <= UINT8_MAX)    {        FCWriteType(FCTypeObjectAlias8, coder->_output);        FCWriteUInt8((uint8_t)index, coder->_output);        return YES;    }    else if (index <= UINT16_MAX)    {        FCWriteType(FCTypeObjectAlias16, coder->_output);        FC_ALIGN_OUTPUT(uint16_t, coder->_output);        FCWriteUInt16((uint16_t)index, coder->_output);        return YES;    }    else if (index != NSNotFound)    {        FCWriteType(FCTypeObjectAlias32, coder->_output);        FC_ALIGN_OUTPUT(uint32_t, coder->_output);        FCWriteUInt32((uint32_t)index, coder->_output);        return YES;    }    else    {        return NO;    }}static inline BOOL FCWriteStringAlias(__unsafe_unretained id object, __unsafe_unretained FCNSCoder *coder){    NSUInteger index = FCIndexOfCachedObject(object, coder->_stringCache);    if (index <= UINT8_MAX)    {      FCWriteType(FCTypeStringAlias8, coder->_output);      FCWriteUInt8((uint8_t)index, coder->_output);      return YES;    }    else if (index <= UINT16_MAX)    {        FCWriteType(FCTypeStringAlias16, coder->_output);        FC_ALIGN_OUTPUT(uint16_t, coder->_output);        FCWriteUInt16((uint16_t)index, coder->_output);        return YES;    }    else if (index != NSNotFound)    {        FCWriteType(FCTypeStringAlias32, coder->_output);        FC_ALIGN_OUTPUT(uint32_t, coder->_output);        FCWriteUInt32((uint32_t)index, coder->_output);        return YES;    }    else    {        return NO;    }}static void FCWriteObject(__unsafe_unretained id object, __unsafe_unretained FCNSCoder *coder){    if (object)    {        [object FC_encodeWithCoder:coder];    }    else    {        FCWriteType(FCTypeNil, coder->_output);    }}@implementation FastCoder+ (id)objectWithData:(NSData *)data{    static FCTypeConstructor *constructors[] =    {        FCReadNil,        FCReadNull,        FCReadAlias8,        FCReadAlias16,        FCReadAlias32,        FCReadStringAlias8,        FCReadStringAlias16,        FCReadStringAlias32,        FCReadString,        FCReadDictionary,        FCReadArray,        FCReadSet,        FCReadOrderedSet,        FCReadTrue,        FCReadFalse,        FCReadInt8,        FCReadInt16,        FCReadInt32,        FCReadInt64,        FCReadFloat32,        FCReadFloat64,        FCReadData,        FCReadDate,        FCReadMutableString,        FCReadMutableDictionary,        FCReadMutableArray,        FCReadMutableSet,        FCReadMutableOrderedSet,        FCReadMutableData,        FCReadClassDefinition,        FCReadObject8,        FCReadObject16,        FCReadObject32,        FCReadURL,        FCReadPoint,        FCReadSize,        FCReadRect,        FCReadRange,        FCReadVector,        FCReadAffineTransform,        FCRead3DTransform,        FCReadMutableIndexSet,        FCReadIndexSet,        FCReadNSCodedObject    };      return FCParseData(data, constructors);}+ (id)propertyListWithData:(NSData *)data{    static FCTypeConstructor *constructors[] =    {        NULL,        FCReadNull,        FCReadAlias8,        FCReadAlias16,        FCReadAlias32,        FCReadStringAlias8,        FCReadStringAlias16,        FCReadStringAlias32,        FCReadString,        FCReadDictionary,        FCReadArray,        FCReadSet,        FCReadOrderedSet,        FCReadTrue,        FCReadFalse,        FCReadInt8,        FCReadInt16,        FCReadInt32,        FCReadInt64,        FCReadFloat32,        FCReadFloat64,        FCReadData,        FCReadDate,        FCReadMutableString,        FCReadMutableDictionary,        FCReadMutableArray,        FCReadMutableSet,        FCReadMutableOrderedSet,        FCReadMutableData,        NULL,        NULL,        NULL,        NULL,        FCReadURL,        FCReadPoint,        FCReadSize,        FCReadRect,        FCReadRange,        FCReadVector,        FCReadAffineTransform,        FCRead3DTransform,        FCReadIndexSet,        FCReadIndexSet,        NULL    };      return FCParseData(data, constructors);}+ (NSData *)dataWithRootObject:(id)object{    if (object)    {        //write header        FCHeader header = {FCIdentifier, FCMajorVersion, FCMinorVersion};        NSMutableData *output = [NSMutableData dataWithLength:sizeof(header)];        memcpy(output.mutableBytes, &header, sizeof(header));                //object count placeholders        FCWriteUInt32(0, output);        FCWriteUInt32(0, output);        FCWriteUInt32(0, output);                //set up cache        const CFDictionaryKeyCallBacks stringKeyCallbacks =        {            0,            NULL,            NULL,            NULL,            CFEqual,            CFHash        };                @autoreleasepool        {            __autoreleasing id objectCache = CFBridgingRelease(CFDictionaryCreateMutable(NULL, 0, NULL, NULL));            __autoreleasing id classCache = CFBridgingRelease(CFDictionaryCreateMutable(NULL, 0, NULL, NULL));            __autoreleasing id stringCache = CFBridgingRelease(CFDictionaryCreateMutable(NULL, 0, &stringKeyCallbacks, NULL));            __autoreleasing id classesByName = CFBridgingRelease(CFDictionaryCreateMutable(NULL, 0, &stringKeyCallbacks, NULL));                      //create coder            FCNSCoder *coder = FC_AUTORELEASE([[FCNSCoder alloc] init]);            coder->_rootObject = object;            coder->_output = output;            coder->_objectCache = objectCache;            coder->_classCache = classCache;            coder->_stringCache = stringCache;            coder->_classesByName = classesByName;                        //write object            FCWriteObject(object, coder);                        //set object count            uint32_t objectCount = (uint32_t)[objectCache count];            [output replaceBytesInRange:NSMakeRange(sizeof(header), sizeof(uint32_t)) withBytes:&objectCount];                      //set class count            uint32_t classCount = (uint32_t)[classCache count];            [output replaceBytesInRange:NSMakeRange(sizeof(header) + sizeof(uint32_t), sizeof(uint32_t)) withBytes:&classCount];                      //set string count            uint32_t stringCount = (uint32_t)[stringCache count];            [output replaceBytesInRange:NSMakeRange(sizeof(header) + sizeof(uint32_t) * 2, sizeof(uint32_t)) withBytes:&stringCount];                        return output;        }    }    return nil;}@end@implementation FCNSCoder- (BOOL)allowsKeyedCoding{    return YES;}- (void)encodeObject:(__unsafe_unretained id)objv forKey:(__unsafe_unretained NSString *)key{    FCWriteObject(objv, self);    FCWriteObject(key, self);}- (void)encodeConditionalObject:(id)objv forKey:(__unsafe_unretained NSString *)key{    if (FCIndexOfCachedObject(objv, _objectCache) != NSNotFound)    {        FCWriteObject(objv, self);        FCWriteObject(key, self);    }}- (void)encodeBool:(BOOL)boolv forKey:(__unsafe_unretained NSString *)key{    FCWriteObject(@(boolv), self);    FCWriteObject(key, self);}- (void)encodeInt:(int)intv forKey:(__unsafe_unretained NSString *)key{    FCWriteObject(@(intv), self);    FCWriteObject(key, self);}- (void)encodeInteger:(NSInteger)intv forKey:(__unsafe_unretained NSString *)key{    FCWriteObject(@(intv), self);    FCWriteObject(key, self);}- (void)encodeInt32:(int32_t)intv forKey:(__unsafe_unretained NSString *)key{    FCWriteObject(@(intv), self);    FCWriteObject(key, self);}- (void)encodeInt64:(int64_t)intv forKey:(__unsafe_unretained NSString *)key{    FCWriteObject(@(intv), self);    FCWriteObject(key, self);}- (void)encodeFloat:(float)realv forKey:(__unsafe_unretained NSString *)key{    FCWriteObject(@(realv), self);    FCWriteObject(key, self);}- (void)encodeDouble:(double)realv forKey:(__unsafe_unretained NSString *)key{    FCWriteObject(@(realv), self);    FCWriteObject(key, self);}- (void)encodeBytes:(const uint8_t *)bytesp length:(NSUInteger)lenv forKey:(__unsafe_unretained NSString *)key{    FCWriteObject([NSData dataWithBytes:bytesp length:lenv], self);    FCWriteObject(key, self);}@end@implementation FCNSDecoder- (BOOL)containsValueForKey:(NSString *)key{    return _properties[key] != nil;}- (id)decodeObjectForKey:(__unsafe_unretained NSString *)key{    return _properties[key];}- (BOOL)decodeBoolForKey:(__unsafe_unretained NSString *)key{    return [_properties[key] boolValue];}- (int)decodeIntForKey:(__unsafe_unretained NSString *)key{    return [_properties[key] intValue];}- (NSInteger)decodeIntegerForKey:(__unsafe_unretained NSString *)key{    return [_properties[key] integerValue];}- (int32_t)decodeInt32ForKey:(__unsafe_unretained NSString *)key{    return (int32_t)[_properties[key] longValue];}- (int64_t)decodeInt64ForKey:(__unsafe_unretained NSString *)key{    return [_properties[key] longLongValue];}- (float)decodeFloatForKey:(__unsafe_unretained NSString *)key{    return [_properties[key] floatValue];}- (double)decodeDoubleForKey:(__unsafe_unretained NSString *)key{    return [_properties[key] doubleValue];}- (const uint8_t *)decodeBytesForKey:(__unsafe_unretained NSString *)key returnedLength:(NSUInteger *)lengthp{    __autoreleasing NSData *data =http://www.mamicode.com/ _properties[key];    *lengthp = [data length];    return data.bytes;}@end@implementation FCClassDefinition : NSObject//no encoding implementation needed@end@implementation NSObject (FastCoding)+ (NSArray *)fastCodingKeys{    __autoreleasing NSMutableArray *codableKeys = [NSMutableArray array];    unsigned int propertyCount;    objc_property_t *properties = class_copyPropertyList(self, &propertyCount);    for (unsigned int i = 0; i < propertyCount; i++)    {        //get property        objc_property_t property = properties[i];        const char *propertyName = property_getName(property);        NSString *key = @(propertyName);                //see if there is a backing ivar        char *ivar = property_copyAttributeValue(property, "V");        if (ivar)        {            //check if ivar has KVC-compliant name            NSString *ivarName = @(ivar);            if ([ivarName isEqualToString:key] || [ivarName isEqualToString:[@"_" stringByAppendingString:key]])            {                //setValue:forKey: will work                [codableKeys addObject:key];            }            free(ivar);        }    }    free(properties);    return codableKeys;}+ (NSArray *)FC_aggregatePropertyKeys{    __autoreleasing NSArray *codableKeys = nil;    codableKeys = objc_getAssociatedObject(self, _cmd);    if (codableKeys == nil)    {        codableKeys = [NSMutableArray array];        Class subclass = [self class];        while (subclass != [NSObject class])        {            [(NSMutableArray *)codableKeys addObjectsFromArray:[subclass fastCodingKeys]];            subclass = [subclass superclass];        }        codableKeys = [NSArray arrayWithArray:codableKeys];                //make the association atomically so that we don‘t need to bother with an @synchronize        objc_setAssociatedObject(self, _cmd, codableKeys, OBJC_ASSOCIATION_RETAIN);    }    return codableKeys;}- (id)awakeAfterFastCoding{    return self;}- (Class)classForFastCoding{    return [self classForCoder];}- (BOOL)preferFastCoding{    return NO;}- (void)FC_encodeWithCoder:(__unsafe_unretained FCNSCoder *)coder{    if (FCWriteObjectAlias(self, coder)) return;        //handle NSCoding    if (![self preferFastCoding] && [self conformsToProtocol:@protocol(NSCoding)])    {        //write object        FCWriteType(FCTypeNSCodedObject, coder->_output);        FCWriteObject(NSStringFromClass([self classForCoder]), coder);        [(id <NSCoding>)self encodeWithCoder:coder];        FCWriteType(FCTypeNil, coder->_output);        FCCacheWrittenObject(self, coder->_objectCache);        return;    }        //write class definition    Class objectClass = [self classForFastCoding];    NSUInteger classIndex = FCIndexOfCachedObject(objectClass, coder->_classCache);    __autoreleasing NSArray *propertyKeys = [objectClass FC_aggregatePropertyKeys];    if (classIndex == NSNotFound)    {        classIndex = FCCacheWrittenObject(objectClass, coder->_classCache);        FCWriteType(FCTypeClassDefinition, coder->_output);        FCWriteString(NSStringFromClass(objectClass), coder->_output);        FC_ALIGN_OUTPUT(uint32_t, coder->_output);        FCWriteUInt32((uint32_t)[propertyKeys count], coder->_output);        for (__unsafe_unretained id value in propertyKeys)        {            FCWriteString(value, coder->_output);        }    }    //write object    FCCacheWrittenObject(self, coder->_objectCache);    if (classIndex <= UINT8_MAX)    {        FCWriteType(FCTypeObject8, coder->_output);        FCWriteUInt8((uint8_t)classIndex, coder->_output);    }    else if (classIndex <= UINT16_MAX)    {        FCWriteType(FCTypeObject16, coder->_output);        FC_ALIGN_OUTPUT(uint16_t, coder->_output);        FCWriteUInt16((uint16_t)classIndex, coder->_output);    }    else    {        FCWriteType(FCTypeObject32, coder->_output);        FC_ALIGN_OUTPUT(uint32_t, coder->_output);        FCWriteUInt32((uint32_t)classIndex, coder->_output);    }    for (__unsafe_unretained NSString *key in propertyKeys)    {        FCWriteObject([self valueForKey:key], coder);    }}@end@implementation NSString (FastCoding)- (void)FC_encodeWithCoder:(__unsafe_unretained FCNSCoder *)coder{    if ([self classForCoder] == [NSMutableString class])    {        if (FCWriteObjectAlias(self, coder)) return;        FCCacheWrittenObject(self, coder->_objectCache);        FCWriteType(FCTypeMutableString, coder->_output);    }    else    {        if (FCWriteStringAlias(self, coder)) return;        FCCacheWrittenObject(self, coder->_stringCache);        FCWriteType(FCTypeString, coder->_output);    }    FCWriteString(self, coder->_output);}@end@implementation NSNumber (FastCoding)- (void)FC_encodeWithCoder:(__unsafe_unretained FCNSCoder *)coder{    switch (CFNumberGetType((CFNumberRef)self))    {        case kCFNumberFloat32Type:        case kCFNumberFloatType:        {            FCWriteType(FCTypeFloat32, coder->_output);            float_t value = [self floatValue];            FC_ALIGN_OUTPUT(float_t, coder->_output);            [coder->_output appendBytes:&value length:sizeof(value)];            break;        }        case kCFNumberFloat64Type:        case kCFNumberDoubleType:        case kCFNumberCGFloatType:        {            FCWriteType(FCTypeFloat64, coder->_output);            double_t value = [self doubleValue];            FC_ALIGN_OUTPUT(double_t, coder->_output);            [coder->_output appendBytes:&value length:sizeof(value)];            break;        }        case kCFNumberSInt64Type:        case kCFNumberLongLongType:        case kCFNumberNSIntegerType:        {            int64_t value = [self longLongValue];            if (value > (int64_t)INT32_MAX || value < (int64_t)INT32_MIN)            {                FCWriteType(FCTypeInt64, coder->_output);                FC_ALIGN_OUTPUT(int64_t, coder->_output);                [coder->_output appendBytes:&value length:sizeof(value)];                break;            }            //otherwise treat as 32-bit        }        case kCFNumberSInt32Type:        case kCFNumberIntType:        case kCFNumberLongType:        case kCFNumberCFIndexType:        {            int32_t value = (int32_t)[self intValue];            if (value > (int32_t)INT16_MAX || value < (int32_t)INT16_MIN)            {                FCWriteType(FCTypeInt32, coder->_output);                FC_ALIGN_OUTPUT(int32_t, coder->_output);                [coder->_output appendBytes:&value length:sizeof(value)];                break;            }            //otherwise treat as 16-bit        }        case kCFNumberSInt16Type:        case kCFNumberShortType:        {            int16_t value = (int16_t)[self intValue];            if (value > (int16_t)INT8_MAX || value < (int16_t)INT8_MIN)            {                FCWriteType(FCTypeInt16, coder->_output);                FC_ALIGN_OUTPUT(int16_t, coder->_output);                [coder->_output appendBytes:&value length:sizeof(value)];                break;            }            //otherwise treat as 8-bit        }        case kCFNumberSInt8Type:        case kCFNumberCharType:        {            int8_t value = (int8_t)[self intValue];            if (value =http://www.mamicode.com/= 1)            {                FCWriteType(FCTypeTrue, coder->_output);            }            else if (value =http://www.mamicode.com/= 0)            {                FCWriteType(FCTypeFalse, coder->_output);            }            else            {                FCWriteType(FCTypeInt8, coder->_output);                [coder->_output appendBytes:&value length:sizeof(value)];            }        }    }}@end@implementation NSDate (FastCoding)- (void)FC_encodeWithCoder:(__unsafe_unretained FCNSCoder *)coder{    FCCacheWrittenObject(self, coder->_objectCache);    FCWriteType(FCTypeDate, coder->_output);    NSTimeInterval value = [self timeIntervalSince1970];    FC_ALIGN_OUTPUT(NSTimeInterval, coder->_output);    [coder->_output appendBytes:&value length:sizeof(value)];}@end@implementation NSData (FastCoding)- (void)FC_encodeWithCoder:(__unsafe_unretained FCNSCoder *)coder{    if (FCWriteObjectAlias(self, coder)) return;    FCCacheWrittenObject(self, coder->_objectCache);    FCWriteType(([self classForCoder] == [NSMutableData class])? FCTypeMutableData: FCTypeData, coder->_output);    uint32_t length = (uint32_t)[self length];    FC_ALIGN_OUTPUT(uint32_t, coder->_output);    FCWriteUInt32(length, coder->_output);    [coder->_output appendData:self];    coder->_output.length += (4 - ((length % 4) ?: 4));}@end@implementation NSNull (FastCoding)- (void)FC_encodeWithCoder:(__unsafe_unretained FCNSCoder *)coder{    FCWriteType(FCTypeNull, coder->_output);}@end@implementation NSDictionary (FastCoding)- (void)FC_encodeWithCoder:(__unsafe_unretained FCNSCoder *)coder{    if (FCWriteObjectAlias(self, coder)) return;        //alias keypath    __autoreleasing NSString *aliasKeypath = self[@"$alias"];    if ([self count] == 1 && aliasKeypath)    {        __autoreleasing id node = coder->_rootObject;        NSArray *parts = [aliasKeypath componentsSeparatedByString:@"."];        for (__unsafe_unretained NSString *key in parts)        {            if ([node isKindOfClass:[NSArray class]])            {                node = ((NSArray *)node)[(NSUInteger)[key integerValue]];            }            else            {                node = [node valueForKey:key];            }        }        FCWriteObject(node, coder);        return;    }        //object bootstrapping    __autoreleasing NSString *className = self[@"$class"];    if (className)    {        //get class definition        __autoreleasing NSArray *propertyKeys = [[self allKeys] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"self != ‘$class‘"]];        __autoreleasing FCClassDefinition *objectClass = coder->_classesByName[className];        if (objectClass)        {            //check that existing class definition contains all keys            __autoreleasing NSMutableArray *keys = nil;            for (__unsafe_unretained id key in propertyKeys)            {                if (![objectClass->_propertyKeys containsObject:key])                {                    keys = keys ?: [NSMutableArray array];                    [keys addObject:key];                }            }            propertyKeys = objectClass->_propertyKeys;            if (keys)            {                //we need to create a new class definition that includes extra keys                propertyKeys = [propertyKeys arrayByAddingObjectsFromArray:keys];                objectClass = nil;            }        }        if (!objectClass)        {            //create class definition            objectClass = FC_AUTORELEASE([[FCClassDefinition alloc] init]);            objectClass->_className = className;            objectClass->_propertyKeys = propertyKeys;            coder->_classesByName[className] = objectClass;        }                //write class definition        NSUInteger classIndex = FCIndexOfCachedObject(objectClass, coder->_classCache);        if (classIndex == NSNotFound)        {            classIndex = FCCacheWrittenObject(objectClass, coder->_classCache);            FCWriteType(FCTypeClassDefinition, coder->_output);            FCWriteString(objectClass->_className, coder->_output);            FC_ALIGN_OUTPUT(uint32_t, coder->_output);            FCWriteUInt32((uint32_t)[propertyKeys count], coder->_output);            for (__unsafe_unretained id key in propertyKeys)            {                //convert each to a string using -description, just in case                FCWriteString([key description], coder->_output);            }        }                //write object        FCCacheWrittenObject(self, coder->_objectCache);        if (classIndex <= UINT8_MAX)        {            FCWriteType(FCTypeObject8, coder->_output);            FCWriteUInt8((uint8_t)classIndex, coder->_output);        }        else if (classIndex <= UINT16_MAX)        {            FCWriteType(FCTypeObject16, coder->_output);            FC_ALIGN_OUTPUT(uint16_t, coder->_output);            FCWriteUInt16((uint16_t)classIndex, coder->_output);        }        else        {            FCWriteType(FCTypeObject32, coder->_output);            FC_ALIGN_OUTPUT(uint32_t, coder->_output);            FCWriteUInt32((uint32_t)classIndex, coder->_output);        }        for (__unsafe_unretained NSString *key in propertyKeys)        {            FCWriteObject(self[key], coder);        }        return;    }        //ordinary dictionary    BOOL mutable = ([self classForCoder] == [NSMutableDictionary class]);    if (mutable) FCCacheWrittenObject(self, coder->_objectCache);    FCWriteType(mutable? FCTypeMutableDictionary: FCTypeDictionary, coder->_output);    FC_ALIGN_OUTPUT(uint32_t, coder->_output);    FCWriteUInt32((uint32_t)[self count], coder->_output);    [self enumerateKeysAndObjectsUsingBlock:^(__unsafe_unretained id key, __unsafe_unretained id obj, __unused BOOL *stop) {        FCWriteObject(obj, coder);        FCWriteObject(key, coder);    }];    if (!mutable) FCCacheWrittenObject(self, coder->_objectCache);}@end@implementation NSArray (FastCoding)- (void)FC_encodeWithCoder:(__unsafe_unretained FCNSCoder *)coder{    if (FCWriteObjectAlias(self, coder)) return;    BOOL mutable = ([self classForCoder] == [NSMutableArray class]);    if (mutable) FCCacheWrittenObject(self, coder->_objectCache);    FCWriteType(mutable? FCTypeMutableArray: FCTypeArray, coder->_output);    FC_ALIGN_OUTPUT(uint32_t, coder->_output);    FCWriteUInt32((uint32_t)[self count], coder->_output);    for (__unsafe_unretained id value in self)    {        FCWriteObject(value, coder);    }    if (!mutable) FCCacheWrittenObject(self, coder->_objectCache);}@end@implementation NSSet (FastCoding)- (void)FC_encodeWithCoder:(__unsafe_unretained FCNSCoder *)coder{    if (FCWriteObjectAlias(self, coder)) return;    BOOL mutable = ([self classForCoder] == [NSMutableSet class]);    if (mutable) FCCacheWrittenObject(self, coder->_objectCache);    FCWriteType(mutable? FCTypeMutableSet: FCTypeSet, coder->_output);    FC_ALIGN_OUTPUT(uint32_t, coder->_output);    FCWriteUInt32((uint32_t)[self count], coder->_output);    for (__unsafe_unretained id value in self)    {        FCWriteObject(value, coder);    }    if (!mutable) FCCacheWrittenObject(self, coder->_objectCache);}@end@implementation NSOrderedSet (FastCoding)- (void)FC_encodeWithCoder:(__unsafe_unretained FCNSCoder *)coder{    if (FCWriteObjectAlias(self, coder)) return;    BOOL mutable = ([self classForCoder] == [NSMutableOrderedSet class]);    if (mutable) FCCacheWrittenObject(self, coder->_objectCache);    FCWriteType(mutable? FCTypeMutableOrderedSet: FCTypeOrderedSet, coder->_output);    FC_ALIGN_OUTPUT(uint32_t, coder->_output);    FCWriteUInt32((uint32_t)[self count], coder->_output);    for (__unsafe_unretained id value in self)    {        FCWriteObject(value, coder);    }    if (!mutable) FCCacheWrittenObject(self, coder->_objectCache);}@end@implementation NSIndexSet (FastCoding)- (void)FC_encodeWithCoder:(__unsafe_unretained FCNSCoder *)coder{    if (FCWriteObjectAlias(self, coder)) return;        BOOL mutable = ([self classForCoder] == [NSMutableIndexSet class]);    if (mutable) FCCacheWrittenObject(self, coder->_objectCache);        uint32_t __block rangeCount = 0; // wish we could get this directly from NSIndexSet...    [self enumerateRangesUsingBlock:^(__unused NSRange range, __unused BOOL *stop) {        rangeCount ++;    }];    FCWriteType(mutable? FCTypeMutableIndexSet: FCTypeIndexSet, coder->_output);    FC_ALIGN_OUTPUT(uint32_t, coder->_output);    FCWriteUInt32(rangeCount, coder->_output);    [self enumerateRangesUsingBlock:^(NSRange range, __unused BOOL *stop) {        FCWriteUInt32((uint32_t)range.location, coder->_output);        FCWriteUInt32((uint32_t)range.length, coder->_output);    }];        if (!mutable) FCCacheWrittenObject(self, coder->_objectCache);}@end@implementation NSURL (FastCoding)- (void)FC_encodeWithCoder:(__unsafe_unretained FCNSCoder *)coder{    if (FCWriteStringAlias(self, coder)) return;    FCWriteType(FCTypeURL, coder->_output);    FCWriteObject(self.relativeString, coder);    FCWriteObject(self.baseURL, coder);    FCCacheWrittenObject(self, coder->_stringCache);}@end@implementation NSValue (FastCoding)- (void)FC_encodeWithCoder:(__unsafe_unretained FCNSCoder *)coder{    FCCacheWrittenObject(self, coder->_objectCache);    const char *type = [self objCType];    if (strcmp(type, @encode(CGPoint)) == 0 OR_IF_MAC(strcmp(type, @encode(NSPoint)) == 0))    {        CGFloat point[2];        [self getValue:&point];        FCWriteType(FCTypePoint, coder->_output);        FC_ALIGN_OUTPUT(double_t, coder->_output);        FCWriteDouble((double_t)point[0], coder->_output);        FCWriteDouble((double_t)point[1], coder->_output);    }    else if (strcmp(type, @encode(CGSize)) == 0 OR_IF_MAC(strcmp(type, @encode(NSSize)) == 0))    {        CGFloat size[2];        [self getValue:&size];        FCWriteType(FCTypeSize, coder->_output);        FC_ALIGN_OUTPUT(double_t, coder->_output);        FCWriteDouble((double_t)size[0], coder->_output);        FCWriteDouble((double_t)size[1], coder->_output);    }    else if (strcmp(type, @encode(CGRect)) == 0 OR_IF_MAC(strcmp(type, @encode(NSRect)) == 0))    {        CGFloat rect[4];        [self getValue:&rect];        FCWriteType(FCTypeRect, coder->_output);        FC_ALIGN_OUTPUT(double_t, coder->_output);        FCWriteDouble((double_t)rect[0], coder->_output);        FCWriteDouble((double_t)rect[1], coder->_output);        FCWriteDouble((double_t)rect[2], coder->_output);        FCWriteDouble((double_t)rect[3], coder->_output);    }    else if (strcmp(type, @encode(NSRange)) == 0)    {        NSUInteger range[2];        [self getValue:&range];        FCWriteType(FCTypeRange, coder->_output);        FC_ALIGN_OUTPUT(uint32_t, coder->_output);        FCWriteUInt32((uint32_t)range[0], coder->_output);        FCWriteUInt32((uint32_t)range[1], coder->_output);    }    else if (strcmp(type, @encode(CGVector)) == 0)    {        CGFloat vector[2];        [self getValue:&vector];        FCWriteType(FCTypeVector, coder->_output);        FC_ALIGN_OUTPUT(double_t, coder->_output);        FCWriteDouble((double_t)vector[0], coder->_output);        FCWriteDouble((double_t)vector[1], coder->_output);    }    else if (strcmp(type, @encode(CGAffineTransform)) == 0)    {        CGFloat transform[6];        [self getValue:&transform];        FCWriteType(FCTypeAffineTransform, coder->_output);        for (NSUInteger i = 0; i < 6; i++)        {            FCWriteDouble((double_t)transform[i], coder->_output);        }    }    else if ([@(type) hasPrefix:@"{CATransform3D"])    {        CGFloat transform[16];        [self getValue:&transform];        FCWriteType(FCType3DTransform, coder->_output);        FC_ALIGN_OUTPUT(double_t, coder->_output);        for (NSUInteger i = 0; i < 16; i++)        {            FCWriteDouble((double_t)transform[i], coder->_output);        }    }    else    {        [NSException raise:FastCodingException format:@"Unable to encode NSValue data of type %@", @(type)];    }}@end#pragma mark -#pragma mark legacy decodingstatic inline uint32_t FCReadRawUInt32_2_3(__unsafe_unretained FCNSDecoder *decoder){    FC_READ_VALUE(uint32_t, *decoder->_offset, decoder->_input, decoder->_total);    return value;}static inline double FCReadRawDouble_2_3(__unsafe_unretained FCNSDecoder *decoder){    FC_READ_VALUE(double_t, *decoder->_offset, decoder->_input, decoder->_total);    return value;}static id FCReadRawString_2_3(__unsafe_unretained FCNSDecoder *decoder){    __autoreleasing NSString *string = nil;    NSUInteger length = strlen(decoder->_input + *decoder->_offset) + 1;    NSUInteger paddedLength = length + (4 - ((length % 4) ?: 4));    FC_ASSERT_FITS(paddedLength, *decoder->_offset, decoder->_total);    if (length > 1)    {        string = CFBridgingRelease(CFStringCreateWithBytes(NULL, decoder->_input + *decoder->_offset,                                                           (CFIndex)length - 1, kCFStringEncodingUTF8, false));    }    else    {        string = @"";    }    *decoder->_offset += paddedLength;    return string;}static id FCReadNull_2_3(__unused __unsafe_unretained FCNSDecoder *decoder){    return [NSNull null];}static id FCReadAlias_2_3(__unsafe_unretained FCNSDecoder *decoder){    return FCCachedObjectAtIndex(FCReadRawUInt32_2_3(decoder), decoder->_objectCache);}static id FCReadString_2_3(__unsafe_unretained FCNSDecoder *decoder){    NSString *string = FCReadRawString_2_3(decoder);    FCCacheReadObject(string, decoder->_objectCache);    return string;}static id FCReadMutableString_2_3(__unsafe_unretained FCNSDecoder *decoder){    __autoreleasing NSMutableString *string = nil;    NSUInteger length = strlen(decoder->_input + *decoder->_offset) + 1;    NSUInteger paddedLength = length + (4 - ((length % 4) ?: 4));    FC_ASSERT_FITS(paddedLength, *decoder->_offset, decoder->_total);    if (length > 1)    {        string = FC_AUTORELEASE([[NSMutableString alloc] initWithBytes:decoder->_input + *decoder->_offset length:length - 1 encoding:NSUTF8StringEncoding]);    }    else    {        string = [NSMutableString string];    }    *decoder->_offset += paddedLength;    FCCacheReadObject(string, decoder->_objectCache);    return string;}static id FCReadDictionary_2_3(__unsafe_unretained FCNSDecoder *decoder){    uint32_t count = FCReadRawUInt32_2_3(decoder);    __autoreleasing NSDictionary *dict = nil;    if (count)    {        __autoreleasing id *keys = (__autoreleasing id *)malloc(count * sizeof(id));        __autoreleasing id *objects = (__autoreleasing id *)malloc(count * sizeof(id));        for (uint32_t i = 0; i < count; i++)        {            objects[i] = FCReadObject_2_3(decoder);            keys[i] = FCReadObject_2_3(decoder);        }                dict = [NSDictionary dictionaryWithObjects:objects forKeys:keys count:count];        free(objects);        free(keys);    }    else    {        dict = @{};    }    FCCacheReadObject(dict, decoder->_objectCache);    return dict;}static id FCReadMutableDictionary_2_3(__unsafe_unretained FCNSDecoder *decoder){    uint32_t count = FCReadRawUInt32_2_3(decoder);    __autoreleasing NSMutableDictionary *dict = CFBridgingRelease(CFDictionaryCreateMutable(NULL, (CFIndex)count, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));    FCCacheReadObject(dict, decoder->_objectCache);    for (uint32_t i = 0; i < count; i++)    {        __autoreleasing id object = FCReadObject_2_3(decoder);        __autoreleasing id key = FCReadObject_2_3(decoder);        CFDictionarySetValue((__bridge CFMutableDictionaryRef)dict, (__bridge const void *)key, (__bridge const void *)object);    }    return dict;}static id FCReadArray_2_3(__unsafe_unretained FCNSDecoder *decoder){    uint32_t count = FCReadRawUInt32_2_3(decoder);    __autoreleasing NSArray *array = nil;    if (count)    {        __autoreleasing id *objects = (__autoreleasing id *)malloc(count * sizeof(id));        for (uint32_t i = 0; i < count; i++)        {            objects[i] = FCReadObject_2_3(decoder);        }        array = [NSArray arrayWithObjects:objects count:count];        free(objects);    }    else    {        array = @[];    }    FCCacheReadObject(array, decoder->_objectCache);    return array;}static id FCReadMutableArray_2_3(__unsafe_unretained FCNSDecoder *decoder){    uint32_t count = FCReadRawUInt32_2_3(decoder);    __autoreleasing NSMutableArray *array = [NSMutableArray arrayWithCapacity:count];    FCCacheReadObject(array, decoder->_objectCache);    for (uint32_t i = 0; i < count; i++)    {        CFArrayAppendValue((__bridge CFMutableArrayRef)array, (__bridge void *)FCReadObject_2_3(decoder));    }    return array;}static id FCReadSet_2_3(__unsafe_unretained FCNSDecoder *decoder){    uint32_t count = FCReadRawUInt32_2_3(decoder);    __autoreleasing NSSet *set = nil;    if (count)    {        __autoreleasing id *objects = (__autoreleasing id *)malloc(count * sizeof(id));        for (uint32_t i = 0; i < count; i++)        {            objects[i] = FCReadObject_2_3(decoder);        }        set = [NSSet setWithObjects:objects count:count];        free(objects);    }    else    {        set = [NSSet set];    }    FCCacheReadObject(set, decoder->_objectCache);    return set;}static id FCReadMutableSet_2_3(__unsafe_unretained FCNSDecoder *decoder){    uint32_t count = FCReadRawUInt32_2_3(decoder);    __autoreleasing NSMutableSet *set = [NSMutableSet setWithCapacity:count];    FCCacheReadObject(set, decoder->_objectCache);    for (uint32_t i = 0; i < count; i++)    {        [set addObject:FCReadObject_2_3(decoder)];    }    return set;}static id FCReadOrderedSet_2_3(__unsafe_unretained FCNSDecoder *decoder){    uint32_t count = FCReadRawUInt32_2_3(decoder);    __autoreleasing NSOrderedSet *set = nil;    if (count)    {        __autoreleasing id *objects = (__autoreleasing id *)malloc(count * sizeof(id));        for (uint32_t i = 0; i < count; i++)        {            objects[i] = FCReadObject_2_3(decoder);        }        set = [NSOrderedSet orderedSetWithObjects:objects count:count];        free(objects);    }    else    {        set = [NSOrderedSet orderedSet];    }    FCCacheReadObject(set, decoder->_objectCache);    return set;}static id FCReadMutableOrderedSet_2_3(__unsafe_unretained FCNSDecoder *decoder){    uint32_t count = FCReadRawUInt32_2_3(decoder);    __autoreleasing NSMutableOrderedSet *set = [NSMutableOrderedSet orderedSetWithCapacity:count];    FCCacheReadObject(set, decoder->_objectCache);    for (uint32_t i = 0; i < count; i++)    {        [set addObject:FCReadObject_2_3(decoder)];    }    return set;}static id FCReadTrue_2_3(__unused __unsafe_unretained FCNSDecoder *decoder){    return @YES;}static id FCReadFalse_2_3(__unused __unsafe_unretained FCNSDecoder *decoder){    return @NO;}static id FCReadInt32_2_3(__unsafe_unretained FCNSDecoder *decoder){    FC_READ_VALUE(int32_t, *decoder->_offset, decoder->_input, decoder->_total);    __autoreleasing NSNumber *number = @(value);    FCCacheReadObject(number, decoder->_objectCache);    return number;}static id FCReadInt64_2_3(__unsafe_unretained FCNSDecoder *decoder){    FC_READ_VALUE(int64_t, *decoder->_offset, decoder->_input, decoder->_total);    __autoreleasing NSNumber *number = @(value);    FCCacheReadObject(number, decoder->_objectCache);    return number;}static id FCReadfloat_t_2_3(__unsafe_unretained FCNSDecoder *decoder){    FC_READ_VALUE(float_t, *decoder->_offset, decoder->_input, decoder->_total);    __autoreleasing NSNumber *number = @(value);    FCCacheReadObject(number, decoder->_objectCache);    return number;}static id FCReaddouble_t_2_3(__unsafe_unretained FCNSDecoder *decoder){    FC_READ_VALUE(double_t, *decoder->_offset, decoder->_input, decoder->_total);    __autoreleasing NSNumber *number = @(value);    FCCacheReadObject(number, decoder->_objectCache);    return number;}static id FCReadData_2_3(__unsafe_unretained FCNSDecoder *decoder){    uint32_t length = FCReadRawUInt32_2_3(decoder);    NSUInteger paddedLength = length + (4 - ((length % 4) ?: 4));    FC_ASSERT_FITS(paddedLength, *decoder->_offset, decoder->_total);    __autoreleasing NSData *data = http://www.mamicode.com/[NSData dataWithBytes:(decoder->_input + *decoder->_offset) length:length];    *decoder->_offset += paddedLength;    FCCacheReadObject(data, decoder->_objectCache);    return data;}static id FCReadMutableData_2_3(__unsafe_unretained FCNSDecoder *decoder){    uint32_t length = FCReadRawUInt32_2_3(decoder);    NSUInteger paddedLength = length + (4 - ((length % 4) ?: 4));    FC_ASSERT_FITS(paddedLength, *decoder->_offset, decoder->_total);    __autoreleasing NSMutableData *data = http://www.mamicode.com/[NSMutableData dataWithBytes:(decoder->_input + *decoder->_offset) length:length];    *decoder->_offset += paddedLength;    FCCacheReadObject(data, decoder->_objectCache);    return data;}static id FCReadDate_2_3(__unsafe_unretained FCNSDecoder *decoder){    FC_READ_VALUE(NSTimeInterval, *decoder->_offset, decoder->_input, decoder->_total);    __autoreleasing NSDate *date = [NSDate dateWithTimeIntervalSince1970:value];    FCCacheReadObject(date, decoder->_objectCache);    return date;}static id FCReadClassDefinition_2_3(__unsafe_unretained FCNSDecoder *decoder){    __autoreleasing FCClassDefinition *definition = FC_AUTORELEASE([[FCClassDefinition alloc] init]);    FCCacheReadObject(definition, decoder->_objectCache);    definition->_className = FCReadRawString_2_3(decoder);    uint32_t count = FCReadRawUInt32_2_3(decoder);    if (count)    {        __autoreleasing id *objects = (__autoreleasing id *)malloc(count * sizeof(id));        for (uint32_t i = 0; i < count; i++)        {            objects[i] = FCReadRawString_2_3(decoder);        }        __autoreleasing NSArray *propertyKeys = [NSArray arrayWithObjects:objects count:count];        definition->_propertyKeys = propertyKeys;        free(objects);    }        //now return the actual object instance    return FCReadObject_2_3(decoder);}static id FCReadObjectInstance_2_3(__unsafe_unretained FCNSDecoder *decoder){    __autoreleasing FCClassDefinition *definition = FCCachedObjectAtIndex(FCReadRawUInt32_2_3(decoder), decoder->_objectCache);    __autoreleasing Class objectClass = NSClassFromString(definition->_className);    __autoreleasing id object = nil;    if (objectClass)    {        object = FC_AUTORELEASE([[objectClass alloc] init]);    }    else if (definition->_className)    {        object = [NSMutableDictionary dictionaryWithObject:definition->_className forKey:@"$class"];    }    else if (object)    {        object = [NSMutableDictionary dictionary];    }    NSUInteger cacheIndex = FCCacheReadObject(object, decoder->_objectCache);    for (__unsafe_unretained NSString *key in definition->_propertyKeys)    {        [object setValue:FCReadObject_2_3(decoder) forKey:key];    }    id newObject = [object awakeAfterFastCoding];    if (newObject != object)    {        //TODO: this is only a partial solution, as any objects that referenced        //this object between when it was created and now will have received incorrect instance        FCReplaceCachedObject(cacheIndex, newObject, decoder->_objectCache);    }    return newObject;}static id FCReadNil_2_3(__unused __unsafe_unretained FCNSDecoder *decoder){    return nil;}static id FCReadURL_2_3(__unsafe_unretained FCNSDecoder *decoder){    __autoreleasing NSURL *URL = [NSURL URLWithString:FCReadObject_2_3(decoder) relativeToURL:FCReadObject_2_3(decoder)];    FCCacheReadObject(URL, decoder->_objectCache);    return URL;}static id FCReadPoint_2_3(__unsafe_unretained FCNSDecoder *decoder){    CGPoint point = {(CGFloat)FCReadRawDouble_2_3(decoder), (CGFloat)FCReadRawDouble_2_3(decoder)};    NSValue *value = http://www.mamicode.com/[NSValue valueWithBytes:&point objCType:@encode(CGPoint)];    FCCacheReadObject(value, decoder->_objectCache);    return value;}static id FCReadSize_2_3(__unsafe_unretained FCNSDecoder *decoder){    CGSize size = {(CGFloat)FCReadRawDouble_2_3(decoder), (CGFloat)FCReadRawDouble_2_3(decoder)};    NSValue *value = http://www.mamicode.com/[NSValue valueWithBytes:&size objCType:@encode(CGSize)];    FCCacheReadObject(value, decoder->_objectCache);    return value;}static id FCReadRect_2_3(__unsafe_unretained FCNSDecoder *decoder){    CGRect rect =    {        {(CGFloat)FCReadRawDouble_2_3(decoder), (CGFloat)FCReadRawDouble_2_3(decoder)},        {(CGFloat)FCReadRawDouble_2_3(decoder), (CGFloat)FCReadRawDouble_2_3(decoder)}    };    NSValue *value = http://www.mamicode.com/[NSValue valueWithBytes:&rect objCType:@encode(CGRect)];    FCCacheReadObject(value, decoder->_objectCache);    return value;}static id FCReadRange_2_3(__unsafe_unretained FCNSDecoder *decoder){    NSRange range = {FCReadRawUInt32_2_3(decoder), FCReadRawUInt32_2_3(decoder)};    NSValue *value = http://www.mamicode.com/[NSValue valueWithBytes:&range objCType:@encode(NSRange)];    FCCacheReadObject(value, decoder->_objectCache);    return value;}static id FCReadAffineTransform_2_3(__unsafe_unretained FCNSDecoder *decoder){    CGAffineTransform transform =    {        (CGFloat)FCReadRawDouble_2_3(decoder), (CGFloat)FCReadRawDouble_2_3(decoder),        (CGFloat)FCReadRawDouble_2_3(decoder), (CGFloat)FCReadRawDouble_2_3(decoder),        (CGFloat)FCReadRawDouble_2_3(decoder), (CGFloat)FCReadRawDouble_2_3(decoder)    };    NSValue *value = http://www.mamicode.com/[NSValue valueWithBytes:&transform objCType:@encode(CGAffineTransform)];    FCCacheReadObject(value, decoder->_objectCache);    return value;}static id FCRead3DTransform_2_3(__unsafe_unretained FCNSDecoder *decoder){    CGFloat transform[] =    {        (CGFloat)FCReadRawDouble_2_3(decoder), (CGFloat)FCReadRawDouble_2_3(decoder),        (CGFloat)FCReadRawDouble_2_3(decoder), (CGFloat)FCReadRawDouble_2_3(decoder),        (CGFloat)FCReadRawDouble_2_3(decoder), (CGFloat)FCReadRawDouble_2_3(decoder),        (CGFloat)FCReadRawDouble_2_3(decoder), (CGFloat)FCReadRawDouble_2_3(decoder),        (CGFloat)FCReadRawDouble_2_3(decoder), (CGFloat)FCReadRawDouble_2_3(decoder),        (CGFloat)FCReadRawDouble_2_3(decoder), (CGFloat)FCReadRawDouble_2_3(decoder),        (CGFloat)FCReadRawDouble_2_3(decoder), (CGFloat)FCReadRawDouble_2_3(decoder),        (CGFloat)FCReadRawDouble_2_3(decoder), (CGFloat)FCReadRawDouble_2_3(decoder)    };    NSValue *value = http://www.mamicode.com/[NSValue valueWithBytes:&transform objCType:@encode(CGFloat[16])];    FCCacheReadObject(value, decoder->_objectCache);    return value;}static id FCReadMutableIndexSet_2_3(__unsafe_unretained FCNSDecoder *decoder){    uint32_t rangeCount = FCReadRawUInt32_2_3(decoder);    __autoreleasing NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet];    FCCacheReadObject(indexSet, decoder->_objectCache);    for (uint32_t i = 0; i < rangeCount; i++)    {        NSRange range = {FCReadRawUInt32_2_3(decoder), FCReadRawUInt32_2_3(decoder)};        [indexSet addIndexesInRange:range];    }    return indexSet;}static id FCReadIndexSet_2_3(__unsafe_unretained FCNSDecoder *decoder){    __autoreleasing NSIndexSet *indexSet;    uint32_t rangeCount = FCReadRawUInt32_2_3(decoder);    if (rangeCount == 1)    {        //common case optimisation        NSRange range = {FCReadRawUInt32_2_3(decoder), FCReadRawUInt32_2_3(decoder)};        indexSet = [NSIndexSet indexSetWithIndexesInRange:range];    }    else    {        indexSet = [NSMutableIndexSet indexSet];        for (uint32_t i = 0; i < rangeCount; i++)        {            NSRange range = {FCReadRawUInt32_2_3(decoder), FCReadRawUInt32_2_3(decoder)};            [(NSMutableIndexSet *)indexSet addIndexesInRange:range];        }        indexSet = [indexSet copy];            }    FCCacheReadObject(indexSet, decoder->_objectCache);    return indexSet;}static id FCReadNSCodedObject_2_3(__unsafe_unretained FCNSDecoder *decoder){    NSString *className = FCReadObject_2_3(decoder);    NSMutableDictionary *oldProperties = decoder->_properties;    decoder->_properties = CFBridgingRelease(CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));    while (true)    {        id object = FCReadObject_2_3(decoder);        if (!object) break;        NSString *key = FCReadObject_2_3(decoder);        decoder->_properties[key] = object;    }    id object = [[NSClassFromString(className) alloc] initWithCoder:decoder];    decoder->_properties = oldProperties;    FCCacheReadObject(object, decoder->_objectCache);    return object;}static id FCReadObject_2_3(__unsafe_unretained FCNSDecoder *decoder){    static FCTypeConstructor *constructors[] =    {        FCReadNull_2_3,        FCReadAlias_2_3,        FCReadString_2_3,        FCReadDictionary_2_3,        FCReadArray_2_3,        FCReadSet_2_3,        FCReadOrderedSet_2_3,        FCReadTrue_2_3,        FCReadFalse_2_3,        FCReadInt32_2_3,        FCReadInt64_2_3,        FCReadfloat_t_2_3,        FCReaddouble_t_2_3,        FCReadData_2_3,        FCReadDate_2_3,        FCReadMutableString_2_3,        FCReadMutableDictionary_2_3,        FCReadMutableArray_2_3,        FCReadMutableSet_2_3,        FCReadMutableOrderedSet_2_3,        FCReadMutableData_2_3,        FCReadClassDefinition_2_3,        FCReadObjectInstance_2_3,        FCReadNil_2_3,        FCReadURL_2_3,        FCReadPoint_2_3,        FCReadSize_2_3,        FCReadRect_2_3,        FCReadRange_2_3,        FCReadAffineTransform_2_3,        FCRead3DTransform_2_3,        FCReadMutableIndexSet_2_3,        FCReadIndexSet_2_3,        FCReadNSCodedObject_2_3    };      uint32_t type = FCReadRawUInt32_2_3(decoder);    if (type > sizeof(constructors))    {        [NSException raise:FastCodingException format:@"FastCoding cannot decode object of type: %i", type];        return nil;    }    return constructors[type](decoder);}

NSObject+FastCoder.h 与 NSObject+FastCoder.m

////  NSObject+FastCoder.h//  Array////  Created by YouXianMing on 14/12/1.//  Copyright (c) 2014年 YouXianMing. All rights reserved.//#import <Foundation/Foundation.h>@interface NSObject (FastCoder)/** *  使用FastCoder将对象写文件 * *  @param path 文件路径 * *  @return YES,成功,NO,失败 */- (BOOL)useFastCoderToWriteToFilePath:(NSString *)filePath;/** *  使用FastCoder从文件路径中恢复对象 * *  @param filePath 文件路径 * *  @return 对象 */- (id)useFastCoderToRecoverFromFilePath:(NSString *)filePath;/** *  使用FastCoder将对象转换成NSData * *  @return NSData */- (NSData *)useFastCoderToCreateData;@end
////  NSObject+FastCoder.m//  Array////  Created by YouXianMing on 14/12/1.//  Copyright (c) 2014年 YouXianMing. All rights reserved.//#import "NSObject+FastCoder.h"#import "FastCoder.h"@implementation NSObject (FastCoder)- (BOOL)useFastCoderToWriteToFilePath:(NSString *)filePath {    BOOL sucess = NO;        if (self) {        NSData *data =http://www.mamicode.com/ [FastCoder dataWithRootObject:self];        sucess       = [data writeToFile:filePath atomically:YES];    }        return sucess;}- (id)useFastCoderToRecoverFromFilePath:(NSString *)filePath {    NSData *data =http://www.mamicode.com/ [NSData dataWithContentsOfFile:filePath];        return [FastCoder objectWithData:data];}- (NSData *)useFastCoderToCreateData {    return [FastCoder dataWithRootObject:self];}@end

 

使用FastCoder写缓存单例