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 @end typedef 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; @end static 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 = [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 = [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 = [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 = [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 = [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 = [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 = [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 = [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 = [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 = _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 == 1) { FCWriteType(FCTypeTrue, coder->_output); } else if (value == 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 decoding static 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 = [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 = [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 = [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 = [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 = [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 = [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 = [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 = [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 = [FastCoder dataWithRootObject:self]; sucess = [data writeToFile:filePath atomically:YES]; } return sucess; } - (id)useFastCoderToRecoverFromFilePath:(NSString *)filePath { NSData *data = [NSData dataWithContentsOfFile:filePath]; return [FastCoder objectWithData:data]; } - (NSData *)useFastCoderToCreateData { return [FastCoder dataWithRootObject:self]; } @end
时间: 2024-10-12 12:47:32