├── .gitignore ├── AutoMagicCoding-iOS.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── AutoMagicCoding ├── NSObject+AutoMagicCoding.h └── NSObject+AutoMagicCoding.m ├── AutomagicCoding.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── CHANGELOG ├── LICENSE ├── NSObject-AutomagicCoding.podspec ├── README.md ├── SupportingFiles ├── SupportingFiles-Mac │ ├── AutomagicCoding-Info.plist │ ├── AutomagicCoding-Prefix.pch │ ├── AutomagicCodingAppDelegate.h │ ├── AutomagicCodingAppDelegate.m │ ├── en.lproj │ │ ├── Credits.rtf │ │ ├── InfoPlist.strings │ │ └── MainMenu.xib │ └── main.m ├── SupportingFiles-Tests-Mac │ ├── AutomagicCodingTests-Info.plist │ └── en.lproj │ │ └── InfoPlist.strings ├── SupportingFiles-Tests-iOS │ ├── AutoMagicCoding-iOSTests-Info.plist │ └── en.lproj │ │ └── InfoPlist.strings └── SupportingFiles-iOS │ ├── AutoMagicCoding-iOS-Info.plist │ ├── AutoMagicCoding-iOS-Prefix.pch │ ├── AutoMagicCoding_iOSAppDelegate.h │ ├── AutoMagicCoding_iOSAppDelegate.m │ ├── en.lproj │ └── InfoPlist.strings │ ├── iPad │ ├── AutoMagicCoding_iOSAppDelegate_iPad.h │ ├── AutoMagicCoding_iOSAppDelegate_iPad.m │ └── en.lproj │ │ └── MainWindow_iPad.xib │ ├── iPhone │ ├── AutoMagicCoding_iOSAppDelegate_iPhone.h │ ├── AutoMagicCoding_iOSAppDelegate_iPhone.m │ └── en.lproj │ │ └── MainWindow_iPhone.xib │ └── main.m └── Tests ├── AMCCollectionsTest.h ├── AMCCollectionsTest.m ├── AMCExceptionsTest.h ├── AMCExceptionsTest.m ├── AMCTest.h ├── AMCTest.m ├── AMCTestSimple.h ├── AMCTestSimple.m └── ObjectsForTests ├── Bar.h ├── Bar.m ├── CCArray.h ├── CCArray.m ├── Foo.h ├── Foo.m ├── FooWithCollections.h ├── FooWithCollections.m ├── FooWithCustomCollection.h ├── FooWithCustomCollection.m ├── FooWithMutableCollections.h ├── FooWithMutableCollections.m ├── FooWithSctructs.h ├── FooWithSctructs.m └── ccCArray.h /.gitignore: -------------------------------------------------------------------------------- 1 | # XCode noise 2 | PLBlocks.framework/* 3 | *.pbxuser 4 | *.mode1v3 5 | *.pyc 6 | *~.nib/ 7 | *.perspective 8 | *.perspectivev3 9 | xcuserdata/ 10 | build/ 11 | 12 | # old school 13 | .svn 14 | 15 | # osx noise 16 | .DS_store 17 | .DS_Store 18 | 19 | # own tmp folder 20 | tmp/ 21 | 22 | -------------------------------------------------------------------------------- /AutoMagicCoding-iOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /AutoMagicCoding/NSObject+AutoMagicCoding.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+AutoMagicCoding.h 3 | // AutoMagicCoding 4 | // ( https://github.com/psineur/NSObject-AutomagicCoding/ ) 5 | // 6 | // 31.08.11. 7 | // Copyright 2011 Stepan Generalov. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #import 28 | #import "objc/runtime.h" 29 | 30 | /** Key for object's class name dictionaryRepresentation. 31 | * Value for this key from dictionary representation used to get Class 32 | * with NSClassFromString(). 33 | */ 34 | #define kAMCDictionaryKeyClassName @"class" 35 | 36 | /** Current version of AutoMagicCoding. */ 37 | extern NSString *const AMCVersion; // = @"1.1" 38 | 39 | /** Custom AMC NSException name for errors while encoding. */ 40 | extern NSString *const AMCEncodeException; 41 | /** Custom AMC NSException name for errors while decoding. */ 42 | extern NSString *const AMCDecodeException; 43 | /** Custom AMC NSException name for detected KVC bugs/failures (see issue #19). */ 44 | extern NSString *const AMCKeyValueCodingFailureException; 45 | 46 | /** Object's fields types recoginzed by AMC. */ 47 | typedef enum 48 | { 49 | /** Scalar value (primitive type or PLIST-compatible non-collection Objects, 50 | * like NSString and NSNumber), that can be saved to NSDictionary without any 51 | * modification of special encoding. 52 | */ 53 | kAMCFieldTypeScalar, 54 | 55 | /** Custom Class objects, derived from NSObject, that returns YES in +AMCEnabled. */ 56 | kAMCFieldTypeCustomObject, 57 | 58 | /** NSDictionary-like objects, that responds to all selectors in AMCHashProtocol */ 59 | kAMCFieldTypeCollectionHash, 60 | 61 | /** NSMutableDictionary-like objects, that responds to all selectors in AMCHashMutableProtocol */ 62 | kAMCFieldTypeCollectionHashMutable, 63 | 64 | /** NSArray-like objects, that responds to all selectors in AMCArrayProtocol */ 65 | kAMCFieldTypeCollectionArray, 66 | 67 | /** NSMutableArray-like objects, that responds to all selectors in AMCArrayMutableProtocol */ 68 | kAMCFieldTypeCollectionArrayMutable, 69 | 70 | /** C structures. */ 71 | kAMCFieldTypeStructure, 72 | } AMCFieldType; 73 | 74 | 75 | #pragma mark Collection Protocols 76 | 77 | /** Protocol that describes selectors, which object must respond to in order to 78 | * be detected by AMC as Ordered Collection. 79 | * Note: object must not conform to this protocol, only respond to it's selectors. 80 | */ 81 | @protocol AMCArrayProtocol 82 | 83 | - (NSUInteger)count; 84 | - (id) objectAtIndex:(NSUInteger) index; 85 | - (id) initWithArray:(NSArray *) array; 86 | 87 | @end 88 | 89 | /** Protocol that describes selectors, which object must respond to in order to 90 | * be detected as Mutable Ordered Collection. 91 | * It simply adds new methods to AMCArrayProtocol. 92 | * Note: object must not conform to this protocol, only respond to it's selectors. 93 | */ 94 | @protocol AMCArrayMutableProtocol 95 | 96 | - (void) addObject: (id) anObject; 97 | 98 | @end 99 | 100 | /** Protocol that describes selectors, which object must respond to in order to 101 | * be detected as Hash(NSDictionary-Like Key-Value) Collection. 102 | * Note: object must not conform to this protocol, only respond to it's selectors. 103 | */ 104 | @protocol AMCHashProtocol 105 | 106 | - (NSUInteger)count; 107 | - (NSArray *) allKeys; 108 | - (id) initWithDictionary: (NSDictionary *) aDict; 109 | 110 | @end 111 | 112 | /** Protocol that describes selectors, which object must respond to in order to 113 | * be detected as Mutable Hash(NSMutableDictionary-Like Key-Value) Collection. 114 | * It simply adds new methods to AMCArrayProtocol. 115 | * Note: object must not conform to this protocol, only respond to it's selectors. 116 | */ 117 | @protocol AMCHashMutableProtocol 118 | 119 | - (void) setObject: (id) anObject forKey:(NSString *) aKey; 120 | 121 | @end 122 | 123 | #pragma mark - AutoMagicCoding Interface 124 | 125 | /** @category AutoMagicCoding AMC Public Interface. Describes new methods, 126 | * added to NSObject by AMC, which you will need to use and/or reimplement 127 | * to support & use serialize/deserialize in your instances of NSObject subclasses. 128 | * @version 1.1 129 | */ 130 | @interface NSObject (AutoMagicCoding) 131 | 132 | /** Used to choose how instances of that class should be treated when encoding/decoding 133 | * and should serialize/deserialize methods work or not. 134 | * Reimplement this method in your classes and return YES if you want to enable 135 | * AutoMagicCoding for your class and it's subclasses. 136 | * Returns NO by default. 137 | */ 138 | + (BOOL) AMCEnabled; 139 | 140 | #pragma mark Decode/Create/Init 141 | 142 | /** Creates autoreleased object with given dictionary representation. 143 | * Returns nil, if aDict is nil or there's no class in your programm with name 144 | * provided in dict for key kAMCDictionaryKeyClassName. 145 | * 146 | * ATTENTION: Can throw exceptions - see README.md "Exceptions" part for details. 147 | * Define AMC_NO_THROW to disable throwing exceptions by this method and make 148 | * it return nil instead. 149 | * 150 | * @param aDict Dictionary that contains name of class NSString for 151 | * kAMCDictionaryKeyClassName key & all other values for keys in the saved object. 152 | */ 153 | + (id) objectWithDictionaryRepresentation: (NSDictionary *) aDict; 154 | 155 | /** Designated initializer for AMC. Treat it as something like -initWithCoder: 156 | * Inits object with key values from given dictionary. 157 | * Doesn't test objectForKey: kAMCDictionaryKeyClassName in aDict to be equal 158 | * with [self className]. 159 | * 160 | * ATTENTION: Can throw exceptions - see README.md "Exceptions" part for details. 161 | * Define AMC_NO_THROW to disable throwing exceptions by this method and make 162 | * it return nil instead. 163 | * 164 | * @param aDict Dictionary that contains name of class NSString for 165 | * kAMCDictionaryKeyClassName key & all other values for keys in the saved object. 166 | */ 167 | - (id) initWithDictionaryRepresentation: (NSDictionary *) aDict; 168 | 169 | /** Works similar to -initWithDictionary: but sets only one value, loaded from 170 | * dictionary representation for given key. 171 | * 172 | * Can be very handy to load only some of values from dictionary representation 173 | * to pass them to existing class init methods. 174 | * 175 | * Uses KVC setValue:forKey: method to set value. 176 | * 177 | * ATTENTION: Can throw exceptions - see README.md "Exceptions" part for details. 178 | * Define AMC_NO_THROW to disable throwing exceptions by this method. 179 | * 180 | * @since v1.1 181 | */ 182 | - (void) loadValueForKey:(NSString *)key fromDictionaryRepresentation: (NSDictionary *) aDict; 183 | 184 | 185 | #pragma mark Encode/Save 186 | 187 | /** Encodes object and returns it's dictionary representation. 188 | * If all encoded object's fields properly supports AMC - returned dictionary 189 | * can be writed to PLIST. 190 | * 191 | * If you can't save returned dictionary to PLIST - it contains 192 | * non-PLIST-compatible objects, probably because some fields doesn't support AMC 193 | * and was treated as kAMCFieldTypeScalar. 194 | * Use "print description" to determine which objects was saved as scalar & add 195 | * AMC support for them. 196 | * 197 | * ATTENTION: Can throw exceptions - see README.md "Exceptions" part for details. 198 | * Define AMC_NO_THROW to disable throwing exceptions by this method and make 199 | * it return nil instead. 200 | */ 201 | - (NSDictionary *) dictionaryRepresentation; 202 | 203 | #pragma mark Structure Support 204 | 205 | /** Returns NSString representation of structure given in NSValue. 206 | * 207 | * Reimplement this method to support your own custom structs. 208 | * When reimplementing - use structName to detect your custom struct type & 209 | * return [super AMCEncodeStructWithValue: value withName: structName] for 210 | * all other struct names. 211 | * (See "Custom Struct Support" part in README.md for details). 212 | * 213 | * Default implementation encodes NS/CG Point, Size & Rect & returns nil if 214 | * structName is not equal to @"NSPoint", @"NSSize", @"NSRect", @"CGPoint", 215 | * @"CGSize" or @"CGRect". 216 | * 217 | * @param structValue NSValue that holds structure to encode. 218 | * 219 | * @param structName Name of structure type to encode. 220 | * In order to receive valid structName - your struct must be encoded/decoded 221 | * with name of it's property - not iVar name. (Issue #10) 222 | * 223 | * ATTENTION: Can throw exceptions - see README.md "Exceptions" part for details. 224 | * Even if AMC_NO_THROW is defined - this method can throw exceptions, that will 225 | * be caught in -dictionaryRepresentation. 226 | * 227 | * You don't need to call this method directly, so don't add @try & @catch blocks to it. 228 | */ 229 | - (NSString *) AMCEncodeStructWithValue: (NSValue *) structValue withName: (NSString *) structName; 230 | 231 | /** Decodes structure from given string & returns NSValue that is ready to be set 232 | * with setValue:forKey:. 233 | * 234 | * Reimplement this method to support your own custom structs. 235 | * When reimplementing - use structName to detect you custom struct type & 236 | * return [super AMCDecodeStructFromString: value withName: structName] for 237 | * all other struct names. 238 | * (See "Custom Struct Support" part in README.md for details). 239 | * 240 | * @param value NSString representation of structure. 241 | * 242 | * @param structName Name of structure type to decode. 243 | * In order to receive valid structName - your struct must be encoded/decoded 244 | * with name of it's property - not iVar name. (Issue #10) 245 | * 246 | * ATTENTION: Can throw exceptions - see README.md "Exceptions" part for details. 247 | * Even if AMC_NO_THROW is defined - this method can throw exceptions, that will 248 | * be caught in -initWithDictionaryRepresentation. 249 | * 250 | * You don't need to call this method directly, so don't add @try & @catch blocks to it. 251 | */ 252 | - (NSValue *) AMCDecodeStructFromString: (NSString *)value withName: (NSString *) structName; 253 | 254 | 255 | #pragma mark Info for Serialization 256 | 257 | /** Returns array of keys, that will be used to create dictionary representation. 258 | * 259 | * By default - uses list of all available properties in the object 260 | * provided by Objective-C Runtime methods. 261 | * All properties declared by superclasses are included. 262 | * Keys order: from superClasses properties first, our object's properties last. 263 | * Inside of each class order: exactly how they was declared - from top 264 | * to bottom. 265 | * NSObject's properties are not included. 266 | * 267 | * You can expand it with your custom non-property ivars, by appending your own 268 | * keys to keys that were returned by [super AMCKeysForDictionaryRepresentation] 269 | * or completely reimplement this method without any call to super - to return 270 | * only keys, that you want to encode/decode. 271 | */ 272 | - (NSArray *) AMCKeysForDictionaryRepresentation; 273 | 274 | /** Returns field type for given key to save/load it in dictionaryRepresentation 275 | * as Scalar, CustomObject, Collection, etc... 276 | * Reimplement this method to add your custom ivar without properties. 277 | * 278 | * ATTENTION: If you've added keys to -AMCKeysForDictionaryRepresentation for 279 | * iVars without properties - you must reimplement this method, or your iVars 280 | * will be treated as kAMCFieldTypeScalar. 281 | * 282 | * Structs always must be used as properties in AMC (Issue #10) - do not 283 | * reimplement this method to support struct iVars - they will be treated 284 | * as structs, but AMC will fail to detect structName, which is needed to 285 | * encode/decode them as NSStrings properly. 286 | */ 287 | - (AMCFieldType) AMCFieldTypeForValueWithKey: (NSString *) aKey; 288 | 289 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED 290 | 291 | /** Returns class name. Declared by AMC for iOS, on Mac declared in Foundation framework */ 292 | - (NSString *) className; 293 | /** Returns class name. Declared by AMC for iOS, on Mac declared in Foundation framework. */ 294 | + (NSString *) className; 295 | 296 | #endif 297 | 298 | @end 299 | 300 | #pragma mark Encode/Decode Helper Functions 301 | 302 | /** Returns value, prepared for -setValue:forKey: based on it's fieldType 303 | * Recursively uses itself for objects in collections. 304 | * You don't need to call this function directly. 305 | */ 306 | id AMCDecodeObject (id value, AMCFieldType fieldType, id collectionClass); 307 | 308 | /** Returns object that can be added to dictionary for dictionaryRepresentation. 309 | * You don't need to call this function directly. 310 | */ 311 | id AMCEncodeObject (id value, AMCFieldType fieldType); 312 | 313 | #pragma mark Property Info Helper Functions 314 | 315 | /** Returns Class of given property if it is a Objective-C object. 316 | * Otherwise returns nil. 317 | * You don't need to call this function directly. 318 | */ 319 | id AMCPropertyClass (objc_property_t property); 320 | 321 | /** Returns name of struct, if given property type is struct. 322 | * Otherwise returns nil. 323 | * You don't need to call this function directly. 324 | */ 325 | NSString *AMCPropertyStructName(objc_property_t property); 326 | 327 | #pragma mark Field Type Info Helper Functions 328 | 329 | /** Tries to guess fieldType for given encoded object. Used in collections 330 | * decoding to create objects in collections. 331 | * You don't need to call this function directly. 332 | */ 333 | AMCFieldType AMCFieldTypeForEncodedObject(id object); 334 | 335 | /** Returns fieldType for given not yet encoded object. 336 | * You don't need to call this function directly. 337 | */ 338 | AMCFieldType AMCFieldTypeForObjectToEncode(id object); 339 | 340 | /** Returns YES, if instances of given class respond to all required instance methods listed 341 | * in protocol p. 342 | * Otherwise returns NO; 343 | * You don't need to call this function directly. 344 | */ 345 | BOOL classInstancesRespondsToAllSelectorsInProtocol(id class, Protocol *p ); 346 | 347 | 348 | -------------------------------------------------------------------------------- /AutoMagicCoding/NSObject+AutoMagicCoding.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+AutoMagicCoding.m 3 | // AutoMagicCoding 4 | // ( https://github.com/psineur/NSObject-AutomagicCoding/ ) 5 | // 6 | // 31.08.11. 7 | // Copyright 2011 Stepan Generalov. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | #import "NSObject+AutoMagicCoding.h" 28 | 29 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED 30 | 31 | #import "UIKit/UIKit.h" 32 | #import "CoreGraphics/CoreGraphics.h" 33 | 34 | #define NSPoint CGPoint 35 | #define NSSize CGSize 36 | #define NSRect CGRect 37 | 38 | #define NSPointFromString CGPointFromString 39 | #define NSSizeFromString CGSizeFromString 40 | #define NSRectFromString CGRectFromString 41 | 42 | #define pointValue CGPointValue 43 | #define sizeValue CGSizeValue 44 | #define rectValue CGRectValue 45 | 46 | #define NSStringFromPoint NSStringFromCGPoint 47 | #define NSStringFromSize NSStringFromCGSize 48 | #define NSStringFromRect NSStringFromCGRect 49 | 50 | #define NSVALUE_ENCODE_POINT(__P__) [NSValue valueWithCGPoint:__P__] 51 | #define NSVALUE_ENCODE_SIZE(__S__) [NSValue valueWithCGSize:__S__] 52 | #define NSVALUE_ENCODE_RECT(__R__) [NSValue valueWithCGRect:__R__] 53 | 54 | #else 55 | 56 | #define NSVALUE_ENCODE_POINT(__P__) [NSValue valueWithPoint:__P__] 57 | #define NSVALUE_ENCODE_SIZE(__S__) [NSValue valueWithSize:__S__] 58 | #define NSVALUE_ENCODE_RECT(__R__) [NSValue valueWithRect:__R__] 59 | 60 | #endif 61 | 62 | NSString *const AMCVersion = @"1.1"; 63 | NSString *const AMCEncodeException = @"AMCEncodeException"; 64 | NSString *const AMCDecodeException = @"AMCDecodeException"; 65 | NSString *const AMCKeyValueCodingFailureException = @"AMCKeyValueCodingFailureException"; 66 | 67 | @implementation NSObject (AutoMagicCoding) 68 | 69 | + (BOOL) AMCEnabled 70 | { 71 | return NO; 72 | } 73 | 74 | #pragma mark Decode/Create/Init 75 | 76 | + (id) objectWithDictionaryRepresentation: (NSDictionary *) aDict 77 | { 78 | if (![aDict isKindOfClass:[NSDictionary class]]) 79 | return nil; 80 | 81 | NSString *className = [aDict objectForKey: kAMCDictionaryKeyClassName]; 82 | if( ![className isKindOfClass:[NSString class]] ) 83 | return nil; 84 | 85 | Class rClass = NSClassFromString(className); 86 | if ( rClass && [rClass instancesRespondToSelector:@selector(initWithDictionaryRepresentation:) ] ) 87 | { 88 | id instance = [[[rClass alloc] initWithDictionaryRepresentation: aDict] autorelease]; 89 | return instance; 90 | } 91 | 92 | return nil; 93 | } 94 | 95 | - (id) initWithDictionaryRepresentation: (NSDictionary *) aDict 96 | { 97 | // NSObject#init simply returns self, so we don't need to call any init here. 98 | // See NSObject Class Reference if you don't trust me ;) 99 | 100 | @try 101 | { 102 | 103 | if (aDict) 104 | { 105 | NSArray *keysForValues = [self AMCKeysForDictionaryRepresentation]; 106 | for (NSString *key in keysForValues) 107 | { 108 | id value = [aDict valueForKey: key]; 109 | if (value) 110 | { 111 | AMCFieldType fieldType = [self AMCFieldTypeForValueWithKey: key]; 112 | objc_property_t property = class_getProperty([self class], [key cStringUsingEncoding:NSUTF8StringEncoding]); 113 | if ( kAMCFieldTypeStructure == fieldType) 114 | { 115 | NSValue *structValue = [self AMCDecodeStructFromString: (NSString *)value withName: AMCPropertyStructName(property)]; 116 | [self setValue: structValue forKey: key]; 117 | } 118 | else 119 | { 120 | id class = AMCPropertyClass(property); 121 | value = AMCDecodeObject(value, fieldType, class); 122 | [self setValue:value forKey: key]; 123 | } 124 | } 125 | } 126 | } 127 | 128 | } 129 | 130 | @catch (NSException *exception) { 131 | [self release]; 132 | 133 | #ifdef AMC_NO_THROW 134 | return nil; 135 | #else 136 | @throw exception; 137 | #endif 138 | } 139 | 140 | return self; 141 | } 142 | 143 | - (void) loadValueForKey:(NSString *)key fromDictionaryRepresentation: (NSDictionary *) aDict 144 | { 145 | @try 146 | { 147 | if (aDict && key) 148 | { 149 | id value = [aDict valueForKey: key]; 150 | if (value) 151 | { 152 | AMCFieldType fieldType = [self AMCFieldTypeForValueWithKey: key]; 153 | objc_property_t property = class_getProperty([self class], [key cStringUsingEncoding:NSUTF8StringEncoding]); 154 | if ( kAMCFieldTypeStructure == fieldType) 155 | { 156 | NSValue *structValue = [self AMCDecodeStructFromString: (NSString *)value withName: AMCPropertyStructName(property)]; 157 | [self setValue: structValue forKey: key]; 158 | } 159 | else 160 | { 161 | id class = AMCPropertyClass(property); 162 | value = AMCDecodeObject(value, fieldType, class); 163 | [self setValue:value forKey: key]; 164 | } 165 | } 166 | } 167 | } 168 | 169 | @catch (NSException *exception) { 170 | 171 | #ifdef AMC_NO_THROW 172 | #else 173 | @throw exception; 174 | #endif 175 | } 176 | } 177 | 178 | #pragma mark Encode/Save 179 | 180 | - (NSDictionary *) dictionaryRepresentation 181 | { 182 | NSArray *keysForValues = [self AMCKeysForDictionaryRepresentation]; 183 | NSMutableDictionary *aDict = [NSMutableDictionary dictionaryWithCapacity:[keysForValues count] + 1]; 184 | 185 | @try 186 | { 187 | for (NSString *key in keysForValues) 188 | { 189 | // Save our current isa, to restore it after using valueForKey:, cause 190 | // it can corrupt it sometimes (sic!), when getting ccColor3B struct via 191 | // property/method. (Issue #19) 192 | Class oldIsa = isa; 193 | 194 | // Get value with KVC as usual. 195 | id value = [self valueForKey: key]; 196 | 197 | if (oldIsa != isa) 198 | { 199 | #ifdef AMC_NO_THROW 200 | NSLog(@"ATTENTION: isa was corrupted, valueForKey: %@ returned %@ It can be garbage!", key, value); 201 | 202 | #else 203 | NSException *exception = [NSException exceptionWithName: AMCKeyValueCodingFailureException 204 | reason: [NSString stringWithFormat:@"ATTENTION: isa was corrupted, valueForKey: %@ returned %@ It can be garbage!", key, value] 205 | userInfo: nil ]; 206 | @throw exception; 207 | #endif 208 | 209 | // Restore isa. 210 | isa = oldIsa; 211 | } 212 | 213 | AMCFieldType fieldType = [self AMCFieldTypeForValueWithKey: key]; 214 | 215 | if ( kAMCFieldTypeStructure == fieldType) 216 | { 217 | objc_property_t property = class_getProperty([self class], [key cStringUsingEncoding:NSUTF8StringEncoding]); 218 | value = [self AMCEncodeStructWithValue: value withName: AMCPropertyStructName(property)]; 219 | } 220 | else 221 | { 222 | value = AMCEncodeObject(value, fieldType); 223 | } 224 | 225 | // Scalar or struct - simply use KVC. 226 | [aDict setValue:value forKey: key]; 227 | } 228 | 229 | [aDict setValue:[self className] forKey: kAMCDictionaryKeyClassName]; 230 | } 231 | @catch (NSException *exception) { 232 | #ifdef AMC_NO_THROW 233 | return nil; 234 | #else 235 | @throw exception; 236 | #endif 237 | } 238 | 239 | return aDict; 240 | } 241 | 242 | 243 | #pragma mark Info for Serialization 244 | 245 | - (NSArray *) AMCKeysForDictionaryRepresentation 246 | { 247 | // Array that will hold properties names. 248 | NSMutableArray *array = [NSMutableArray arrayWithCapacity: 0]; 249 | 250 | // Go through superClasses from self class to NSObject to get all inherited properties. 251 | id curClass = [self class]; 252 | while (1) 253 | { 254 | // Stop on NSObject. 255 | if (curClass && curClass == [NSObject class]) 256 | break; 257 | 258 | // Use objc runtime to get all properties and return their names. 259 | unsigned int outCount; 260 | objc_property_t *properties = class_copyPropertyList(curClass, &outCount); 261 | 262 | // Reverse order of curClass properties, cause we will return reversed array. 263 | for (int i = outCount - 1; i >= 0; --i) 264 | { 265 | objc_property_t curProperty = properties[i]; 266 | const char *name = property_getName(curProperty); 267 | 268 | NSString *propertyKey = [NSString stringWithCString:name encoding:NSUTF8StringEncoding]; 269 | [array addObject: propertyKey]; 270 | } 271 | 272 | if (properties) 273 | free(properties); 274 | 275 | // Next. 276 | curClass = [curClass superclass]; 277 | } 278 | 279 | id result = [[array reverseObjectEnumerator] allObjects]; 280 | 281 | return result; 282 | } 283 | 284 | - (AMCFieldType) AMCFieldTypeForValueWithKey: (NSString *) aKey 285 | { 286 | // isAutoMagicCodingEnabled == YES? Then it's custom object. 287 | objc_property_t property = class_getProperty([self class], [aKey cStringUsingEncoding:NSUTF8StringEncoding]); 288 | id class = AMCPropertyClass(property); 289 | 290 | if ([class AMCEnabled]) 291 | return kAMCFieldTypeCustomObject; 292 | 293 | // Is it ordered collection? 294 | if ( classInstancesRespondsToAllSelectorsInProtocol(class, @protocol(AMCArrayProtocol) ) ) 295 | { 296 | // Mutable? 297 | if ( classInstancesRespondsToAllSelectorsInProtocol(class, @protocol(AMCArrayMutableProtocol) ) ) 298 | return kAMCFieldTypeCollectionArrayMutable; 299 | 300 | // Not Mutable. 301 | return kAMCFieldTypeCollectionArray; 302 | } 303 | 304 | // Is it hash collection? 305 | if ( classInstancesRespondsToAllSelectorsInProtocol(class, @protocol(AMCHashProtocol) ) ) 306 | { 307 | // Mutable? 308 | if ( classInstancesRespondsToAllSelectorsInProtocol(class, @protocol(AMCHashMutableProtocol) ) ) 309 | return kAMCFieldTypeCollectionHashMutable; 310 | 311 | // Not Mutable. 312 | return kAMCFieldTypeCollectionHash; 313 | } 314 | 315 | // Is it a structure? 316 | NSString *structName = AMCPropertyStructName(property); 317 | if (structName) 318 | return kAMCFieldTypeStructure; 319 | 320 | // Otherwise - it's a scalar or PLIST-Compatible object (i.e. NSString) 321 | return kAMCFieldTypeScalar; 322 | } 323 | 324 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED 325 | 326 | - (NSString *) className 327 | { 328 | const char* name = class_getName([self class]); 329 | 330 | return [NSString stringWithCString:name encoding:NSUTF8StringEncoding]; 331 | } 332 | 333 | + (NSString *) className 334 | { 335 | const char* name = class_getName([self class]); 336 | 337 | return [NSString stringWithCString:name encoding:NSUTF8StringEncoding]; 338 | } 339 | 340 | #endif 341 | 342 | #pragma mark Structure Support 343 | 344 | - (NSValue *) AMCDecodeStructFromString: (NSString *)value withName: (NSString *) structName 345 | { 346 | // valueForKey: never returns CGPoint, CGRect, etc - it returns NSPoint, NSRect stored in NSValue instead. 347 | // This is why here was made no difference between struct names such CGP 348 | 349 | if ([structName isEqualToString:@"CGPoint"] || [structName isEqualToString:@"NSPoint"]) 350 | { 351 | NSPoint p = NSPointFromString(value); 352 | 353 | return NSVALUE_ENCODE_POINT(p); 354 | } 355 | else if ([structName isEqualToString:@"CGSize"] || [structName isEqualToString:@"NSSize"]) 356 | { 357 | NSSize s = NSSizeFromString(value); 358 | 359 | return NSVALUE_ENCODE_SIZE(s); 360 | } 361 | else if ([structName isEqualToString:@"CGRect"] || [structName isEqualToString:@"NSRect"]) 362 | { 363 | NSRect r = NSRectFromString(value); 364 | 365 | return NSVALUE_ENCODE_RECT(r); 366 | } 367 | 368 | if (!structName) 369 | structName = @"(null)"; 370 | NSException *exception = [NSException exceptionWithName: AMCDecodeException 371 | reason: [NSString stringWithFormat:@"AMCDecodeException: %@ is unsupported struct.", structName] 372 | userInfo: nil ]; 373 | 374 | @throw exception; 375 | 376 | return nil; 377 | } 378 | 379 | - (NSString *) AMCEncodeStructWithValue: (NSValue *) structValue withName: (NSString *) structName 380 | { 381 | // valueForKey: never returns CGPoint, CGRect, etc - it returns NSPoint, NSRect stored in NSValue instead. 382 | // This is why here was made no difference between struct names such CGPoint & NSPoint. 383 | 384 | if ( [structName isEqualToString:@"CGPoint"] || [structName isEqualToString:@"NSPoint"]) 385 | { 386 | NSPoint point = [structValue pointValue]; 387 | 388 | return NSStringFromPoint(point); 389 | } 390 | else if ( [structName isEqualToString:@"CGSize"] || [structName isEqualToString:@"NSSize"]) 391 | { 392 | NSSize size = [structValue sizeValue]; 393 | 394 | return NSStringFromSize(size); 395 | } 396 | else if ( [structName isEqualToString:@"CGRect"] || [structName isEqualToString:@"NSRect"]) 397 | { 398 | NSRect rect = [structValue rectValue]; 399 | 400 | return NSStringFromRect(rect); 401 | } 402 | 403 | if (!structName) 404 | structName = @"(null)"; 405 | NSException *exception = [NSException exceptionWithName: AMCEncodeException 406 | reason: [NSString stringWithFormat:@"AMCEncodeException: %@ is unsupported struct.", structName] 407 | userInfo: nil ]; 408 | 409 | @throw exception; 410 | 411 | return nil; 412 | } 413 | 414 | @end 415 | 416 | 417 | #pragma mark Helper Functions 418 | 419 | id AMCPropertyClass (objc_property_t property) 420 | { 421 | if (!property) 422 | return nil; 423 | 424 | const char *attributes = property_getAttributes(property); 425 | char *classNameCString = strstr(attributes, "@\""); 426 | if ( classNameCString ) 427 | { 428 | classNameCString += 2; //< skip @" substring 429 | NSString *classNameString = [NSString stringWithCString:classNameCString encoding:NSUTF8StringEncoding]; 430 | NSRange range = [classNameString rangeOfString:@"\""]; 431 | 432 | classNameString = [classNameString substringToIndex: range.location]; 433 | 434 | id class = NSClassFromString(classNameString); 435 | return class; 436 | } 437 | 438 | return nil; 439 | } 440 | 441 | NSString *AMCPropertyStructName(objc_property_t property) 442 | { 443 | if (!property) 444 | return nil; 445 | 446 | const char *attributes = property_getAttributes(property); 447 | char *structNameCString = strstr(attributes, "T{"); 448 | if ( structNameCString ) 449 | { 450 | structNameCString += 2; //< skip T{ substring 451 | NSString *structNameString = [NSString stringWithCString:structNameCString encoding:NSUTF8StringEncoding]; 452 | NSRange range = [structNameString rangeOfString:@"="]; 453 | 454 | structNameString = [structNameString substringToIndex: range.location]; 455 | 456 | return structNameString; 457 | } 458 | 459 | return nil; 460 | } 461 | 462 | BOOL classInstancesRespondsToAllSelectorsInProtocol(id class, Protocol *p ) 463 | { 464 | unsigned int outCount = 0; 465 | struct objc_method_description *methods = NULL; 466 | 467 | methods = protocol_copyMethodDescriptionList( p, YES, YES, &outCount); 468 | 469 | for (unsigned int i = 0; i < outCount; ++i) 470 | { 471 | SEL selector = methods[i].name; 472 | if (![class instancesRespondToSelector: selector]) 473 | { 474 | if (methods) 475 | free(methods); 476 | methods = NULL; 477 | 478 | return NO; 479 | } 480 | } 481 | 482 | if (methods) 483 | free(methods); 484 | methods = NULL; 485 | 486 | return YES; 487 | } 488 | 489 | id AMCDecodeObject (id value, AMCFieldType fieldType, id collectionClass ) 490 | { 491 | switch (fieldType) 492 | { 493 | 494 | // Object as it's representation - create new. 495 | case kAMCFieldTypeCustomObject: 496 | { 497 | id object = [NSObject objectWithDictionaryRepresentation: (NSDictionary *) value]; 498 | 499 | // Here was following code: 500 | // if (object) 501 | // value = object; 502 | // 503 | // It was replaced with this one: 504 | 505 | value = object; 506 | 507 | // To pass -testIntToObjectDecode added in b5522b23a4b484359dca32ddfd38e9dff51bc853 508 | // In that test dictionaryRepresentation was modified and NSNumber (kAMCFieldTypeScalar) 509 | // was set to field with type kAMCFieldTypeCustomObject. 510 | // So there was NSNumber object set instead of Bar in that test. 511 | // It's possible to modify dictionaryRepresentation so, that one custom object 512 | // will be set instead of other custom object, but if -objectWithDictionaryRepresentation 513 | // returns nil - that definetly can't be set as customObject. 514 | 515 | } 516 | break; 517 | 518 | 519 | case kAMCFieldTypeCollectionArray: 520 | case kAMCFieldTypeCollectionArrayMutable: 521 | { 522 | // Create temporary array of all objects in collection. 523 | id srcCollection = (id ) value; 524 | NSMutableArray *dstCollection = [NSMutableArray arrayWithCapacity:[srcCollection count]]; 525 | for (unsigned int i = 0; i < [srcCollection count]; ++i) 526 | { 527 | id curEncodedObjectInCollection = [srcCollection objectAtIndex: i]; 528 | id curDecodedObjectInCollection = AMCDecodeObject( curEncodedObjectInCollection, AMCFieldTypeForEncodedObject(curEncodedObjectInCollection), nil ); 529 | [dstCollection addObject: curDecodedObjectInCollection]; 530 | } 531 | 532 | // Get Collection Array Class from property and create object 533 | id class = collectionClass; 534 | if (!collectionClass) 535 | { 536 | if (kAMCFieldTypeCollectionArray) 537 | class = [NSArray class]; 538 | else 539 | class = [NSMutableArray class]; 540 | } 541 | 542 | id object = (id )[class alloc]; 543 | @try 544 | { 545 | object = [object initWithArray: dstCollection]; 546 | } 547 | @finally { 548 | [object autorelease]; 549 | } 550 | 551 | if (object) 552 | value = object; 553 | } 554 | break; 555 | 556 | case kAMCFieldTypeCollectionHash: 557 | case kAMCFieldTypeCollectionHashMutable: 558 | { 559 | // Create temporary array of all objects in collection. 560 | NSObject *srcCollection = (NSObject *) value; 561 | NSMutableDictionary *dstCollection = [NSMutableDictionary dictionaryWithCapacity:[srcCollection count]]; 562 | for (NSString *curKey in [srcCollection allKeys]) 563 | { 564 | id curEncodedObjectInCollection = [srcCollection valueForKey: curKey]; 565 | id curDecodedObjectInCollection = AMCDecodeObject( curEncodedObjectInCollection, AMCFieldTypeForEncodedObject(curEncodedObjectInCollection), nil ); 566 | [dstCollection setObject: curDecodedObjectInCollection forKey: curKey]; 567 | } 568 | 569 | // Get Collection Array Class from property and create object 570 | id class = collectionClass; 571 | if (!collectionClass) 572 | { 573 | if (kAMCFieldTypeCollectionArray) 574 | class = [NSDictionary class]; 575 | else 576 | class = [NSMutableDictionary class]; 577 | } 578 | 579 | id object = (id )[class alloc]; 580 | @try 581 | { 582 | object = [object initWithDictionary: dstCollection]; 583 | } 584 | @finally { 585 | [object autorelease]; 586 | } 587 | 588 | if (object) 589 | value = object; 590 | } break; 591 | 592 | // Scalar or struct - simply use KVC. 593 | case kAMCFieldTypeScalar: 594 | break; 595 | default: 596 | break; 597 | } 598 | 599 | return value; 600 | } 601 | 602 | id AMCEncodeObject (id value, AMCFieldType fieldType) 603 | { 604 | switch (fieldType) 605 | { 606 | 607 | // Object as it's representation - create new. 608 | case kAMCFieldTypeCustomObject: 609 | { 610 | if ([value respondsToSelector:@selector(dictionaryRepresentation)]) 611 | value = [(NSObject *) value dictionaryRepresentation]; 612 | } 613 | break; 614 | 615 | case kAMCFieldTypeCollectionArray: 616 | case kAMCFieldTypeCollectionArrayMutable: 617 | { 618 | 619 | id collection = (id )value; 620 | NSMutableArray *tmpArray = [NSMutableArray arrayWithCapacity: [collection count]]; 621 | 622 | for (unsigned int i = 0; i < [collection count]; ++i) 623 | { 624 | NSObject *curObjectInCollection = [collection objectAtIndex: i]; 625 | NSObject *curObjectInCollectionEncoded = AMCEncodeObject (curObjectInCollection, AMCFieldTypeForObjectToEncode(curObjectInCollection) ); 626 | 627 | [tmpArray addObject: curObjectInCollectionEncoded]; 628 | } 629 | 630 | value = tmpArray; 631 | } 632 | break; 633 | 634 | case kAMCFieldTypeCollectionHash: 635 | case kAMCFieldTypeCollectionHashMutable: 636 | { 637 | NSObject *collection = (NSObject *)value; 638 | NSMutableDictionary *tmpDict = [NSMutableDictionary dictionaryWithCapacity: [collection count]]; 639 | 640 | for (NSString *curKey in [collection allKeys]) 641 | { 642 | NSObject *curObjectInCollection = [collection valueForKey: curKey]; 643 | NSObject *curObjectInCollectionEncoded = AMCEncodeObject (curObjectInCollection, AMCFieldTypeForObjectToEncode(curObjectInCollection)); 644 | 645 | [tmpDict setObject:curObjectInCollectionEncoded forKey:curKey]; 646 | } 647 | 648 | value = tmpDict; 649 | } 650 | break; 651 | 652 | 653 | // Scalar or struct - simply use KVC. 654 | case kAMCFieldTypeScalar: 655 | break; 656 | default: 657 | break; 658 | } 659 | 660 | return value; 661 | } 662 | 663 | AMCFieldType AMCFieldTypeForEncodedObject(id object) 664 | { 665 | id class = [object class]; 666 | 667 | // Is it ordered collection? 668 | if ( classInstancesRespondsToAllSelectorsInProtocol(class, @protocol(AMCArrayProtocol) ) ) 669 | { 670 | // Mutable? 671 | if ( classInstancesRespondsToAllSelectorsInProtocol(class, @protocol(AMCArrayMutableProtocol) ) ) 672 | return kAMCFieldTypeCollectionArrayMutable; 673 | 674 | // Not Mutable. 675 | return kAMCFieldTypeCollectionArray; 676 | } 677 | 678 | // Is it hash collection? 679 | if ( classInstancesRespondsToAllSelectorsInProtocol(class, @protocol(AMCHashProtocol) ) ) 680 | { 681 | 682 | // Maybe it's custom object encoded in NSDictionary? 683 | if ([object respondsToSelector:@selector(objectForKey:)]) 684 | { 685 | NSString *className = [object objectForKey:kAMCDictionaryKeyClassName]; 686 | if ([className isKindOfClass:[NSString class]]) 687 | { 688 | id encodedObjectClass = NSClassFromString(className); 689 | 690 | if ([encodedObjectClass AMCEnabled]) 691 | return kAMCFieldTypeCustomObject; 692 | } 693 | } 694 | 695 | // Mutable? 696 | if ( classInstancesRespondsToAllSelectorsInProtocol(class, @protocol(AMCHashMutableProtocol) ) ) 697 | return kAMCFieldTypeCollectionHashMutable; 698 | 699 | // Not Mutable. 700 | return kAMCFieldTypeCollectionHash; 701 | } 702 | 703 | 704 | return kAMCFieldTypeScalar; 705 | } 706 | 707 | 708 | 709 | AMCFieldType AMCFieldTypeForObjectToEncode(id object) 710 | { 711 | id class = [object class]; 712 | 713 | // Is it custom object with dictionaryRepresentation support? 714 | if (([[object class] AMCEnabled] 715 | && ([object respondsToSelector:@selector(dictionaryRepresentation)])) 716 | ) 717 | { 718 | return kAMCFieldTypeCustomObject; 719 | } 720 | 721 | // Is it ordered collection? 722 | if ( classInstancesRespondsToAllSelectorsInProtocol(class, @protocol(AMCArrayProtocol) ) ) 723 | { 724 | // Mutable? 725 | if ( classInstancesRespondsToAllSelectorsInProtocol(class, @protocol(AMCArrayMutableProtocol) ) ) 726 | return kAMCFieldTypeCollectionArrayMutable; 727 | 728 | // Not Mutable. 729 | return kAMCFieldTypeCollectionArray; 730 | } 731 | 732 | // Is it hash collection? 733 | if ( classInstancesRespondsToAllSelectorsInProtocol(class, @protocol(AMCHashProtocol) ) ) 734 | { 735 | // Mutable? 736 | if ( classInstancesRespondsToAllSelectorsInProtocol(class, @protocol(AMCHashMutableProtocol) ) ) 737 | return kAMCFieldTypeCollectionHashMutable; 738 | 739 | // Not Mutable. 740 | return kAMCFieldTypeCollectionHash; 741 | } 742 | 743 | return kAMCFieldTypeScalar; 744 | } 745 | 746 | 747 | 748 | 749 | 750 | -------------------------------------------------------------------------------- /AutomagicCoding.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | 2 | 1.1.1 - 1-Apr-2013 3 | * [NEW] Cocoapods support 4 | 5 | 1.1 - 31-Jan-2012 6 | * [NEW] Added -loadValueForKey:fromDictionaryRepresentation: method. 7 | * [FIX] Default implementation of AMCKeysForDictionaryRepresentation returns complete set of all object's properties names, including properties declared by superclasses. ( Issue #15 ) 8 | * [FIX] Added Log, Workaround ( when AMC_NO_THROW defined) & Exception ( when AMC_NO_THROW not defined) on possible KVC failure/bug (Issue #19). 9 | * [FIX] Fixed missed imports in NSObject+AutoMagicCoding.m, which may lead to inability to compile AMC as a part of libs (no compile error occurred, but AMC wasn't included in library). 10 | 11 | 1.0 - 18-Dec-2011 12 | * Initial release with following features: 13 | * Supported: Primitive & PLIST-compatible types, Custom Objects, Structs(Point/Rect/Size for Mac/iOS), Custom Structs, Collections, Custom class Collections. 14 | * Ability to turn exceptions on/off (AMC_NO_THROW) . 15 | * Mac / iOS Support. 16 | 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | AMC is licensed under terms & conditions of MIT License. 2 | http://www.opensource.org/licenses/mit-license.php 3 | 4 | Copyright 2011 Stepan Generalov. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. -------------------------------------------------------------------------------- /NSObject-AutomagicCoding.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'NSObject-AutomagicCoding' 3 | s.version = '1.1.1' 4 | s.license = { :type => 'MIT' } 5 | s.authors = { 'Stepan Generalov' => 'psi.pk.ru@gmail.com' } 6 | s.summary = 'Very easy to use NSCoding replacement for Mac and iOS Projects.' 7 | s.homepage = 'https://github.com/psineur/NSObject-AutomagicCoding' 8 | s.source = { :git => 'https://github.com/psineur/NSObject-AutomagicCoding.git', :tag => 'v1.1.1' } 9 | s.source_files = 'AutoMagicCoding/NSObject+AutoMagicCoding.{h,m}' 10 | s.requires_arc = false 11 | end 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | AMC 2 | ================== 3 | __AMC is AutoMagic Coding__ - very easy to use NSCoding replacement for Mac & iOS Projects. 4 | AMC gives you ability to create NSDictionary representation of any supported object, save it in PLIST 5 | (or any other PLIST-compatible file format, i.e. JSON) and load again without writing a lot of code. 6 | 7 | AMC uses Objective-C Runtime to determine object's properties automatically & Key-Value-Coding to 8 | get & set them. 9 | 10 | Repo Contents 11 | ------------------------------------- 12 | 13 | * __AutoMagicCoding/__ - contains all AMC sources, that you need to import to your project. 14 | * __Tests/__ - contains all AMC Unit Tests sources. 15 | * __ObjectsForTests/__ - contains test classes, that are used in Unit Tests. Good examples how to use AMC. 16 | * __SupportingFiles/__ - XCode stuff (Info.plists, xibs, main.m, etc...) 17 | * AutoMagicCoding.xcodeproj - Mac XCode Project for testing AMC on Mac. 18 | * AutoMagicCoding-iOS.xcodeproj - iOS XCode Project for testing AMC on iOS. 19 | * README.md - contains text that you're reading right now. ;) 20 | 21 | Supported properties types 22 | ------------------------------------- 23 | * AMC Enabled Objects. 24 | * Common Collections (NSArray, NSMutableArray, NSDictionary, NSMutableDictionary) 25 | * Custom Collections (Mutable/Not-Mutable, that can be used as keyValue(Dictionary) or Ordered(Array) collections ) 26 | * Note: Custom and/or Mutable Collections will not be recognized inside of collections itself. Ordered collections will be treated as NSArray, keyValue collections will be treated as NSDictionary. 27 | * Common Structures (NSRect/CGRect, NSSize/CGSize, NSPoint/CGPoint). 28 | * Custom Structures (You will need to write additional code to encode/decode them to/from NSString). 29 | 30 | File Format 31 | ------------------------------------- 32 | 33 | AMC saves object to NSDictionary, that can be saved to PLIST (or JSON). 34 | Keys simply are ivars names and/or properties names. 35 | One special key ( "class" ) used to hold name of the object's class. 36 | Run unit tests on Mac & go look to your Documents folder - there will be a lot of PLISTs. 37 | They are test objects saved to PLIST files. 38 | 39 | Known Issues 40 | ================== 41 | * Structures can't be iVars - they must be used in AMC as properties (Issue #10) . 42 | * There's some troubles in XCode running Unit Tests on iOS. See Issue #9 for details. 43 | 44 | How To Use 45 | ================== 46 | 1. Drag'n'Drop NSObject+AutoMagicCoding.h | m to your project. This will add AMC methods to all objects 47 | inherited from NSObject. 48 | 2. Import NSObject+AutoMagicCoding.h where you need it. 49 | 3. Reimplement +(BOOL)AMCEnabled and return YES to enable AMC for all instances of your class. 50 | 4. Reimplement -(id)initWithDictionaryRepresentation: and use [super initWithDictionaryRepresentation] inside of it. Ensure that all collections & other fields are created 51 | after calling super initWithDictionaryRepresentation. Do your own init routines after. 52 | 4. Use -dictionaryRepresentation to encode your object to NSDictionary & NSObject::objectWithDictionaryRepresentation: to decode. 53 | * __Additionaly:__ reimplement -AMCKeysForDictionaryRepresentation to change amount & order of encoded/decoded fields. (See AMCKeysForDictionaryRepresentation below for more info ). 54 | * __Additionaly:__ reimplement -AMCEncodeStructWithValue:withName: & -AMCDecodeStructWithValue: withName: to support custom structs (See Custom Struct below for more info). 55 | * __Additionaly:__ reimplement -AMCFieldTypeForValueWithKey: for any non-scalar ivars, that you want to use 56 | as fields for AMC. 57 | 58 | __ATTENTION__: It's recommended to avoid using iVars without properties in AMC due to 59 | harder memory management, need to write more code, unsupported custom structs & possible future restrictions. 60 | 61 | AMCKeysForDictionaryRepresentation 62 | ================== 63 | 64 | -AMCKeysForDictionaryRepresentation returns NSArray of NSStrings, thar are passed to KVC methods 65 | to get & set fields of AMCEnabled objects. 66 | Default implementation returns complete set of all object properties (both readonly & readwrite), 67 | including properties declared by superclasses (NSObject's properties are not included). 68 | Reimplement this method to choose manually, what properties should be encoded/decoded by AMC. 69 | See tests in "Tests" folder for more info & usage examples. 70 | 71 | Custom Struct Support 72 | ================== 73 | 74 | To support your own custom structs you must do the following: 75 | 76 | 1. Your custom structs should be used __ONLY AS PROPERTIES__ in your classes. iVars custom structs are not supported. 77 | 2. Reimplement -AMCEncodeStructWithValue:withName: & AMCDecodeStructFromString:withName: like this: 78 | 79 | ``` 80 | - (NSString *) AMCEncodeStructWithValue: (NSValue *) structValue withName: (NSString *) structName 81 | { 82 | if ([structName isEqualToString: @"CustomStruct" ]) 83 | { 84 | CustomStruct custom; 85 | [structValue getValue: &custom]; 86 | 87 | return NSStringFromCustomStruct(custom); 88 | } 89 | 90 | return [super AMCEncodeStructWithValue: structValue withName: structName]; 91 | } 92 | 93 | - (NSValue *) AMCDecodeStructFromString: (NSString *)value withName: (NSString *) structName 94 | { 95 | if ([structName isEqualToString: @"CustomStruct" ]) 96 | { 97 | CustomStruct custom = CustomStructFromNSString(value); 98 | return [NSValue valueWithBytes: &custom objCType:@encode(CustomStruct)]; 99 | } 100 | 101 | return [super AMCDecodeStructFromString: value withName: structName]; 102 | } 103 | ``` 104 | 105 | See FooWithStructs & AMCTestSimple for working example. 106 | 107 | 108 | Exceptions 109 | ================== 110 | 111 | All exceptions, bad-data & unwanted behaviour tests are located in AMCExceptions.m. 112 | 113 | Here's a list of bad things, that can happen with AMC: 114 | 115 | * __Encoding__ ( calling -dictionaryRepresentation ) 116 | 1. **Unsupported struct**: throws AMCEncodeException (See Custom Struct Support above). 117 | 2. **Wrong keys in -AMCKeysForDictionaryRepresentation**: Throws NSUnkownKeyException.( Wrong key = no such property, ivar or method - see KVC programming guide for details). 118 | 3. **KVC bug/failure, when using -valueForKey: with method/property on struct with size that is not multiple of 4**: Throws AMCKeyValueCodingFailureException (Issue #19). 119 | * __Decoding__ ( calling +objectWithDictionaryRepresentation: & -initWithDictionaryRepresentation: ) 120 | 1. **Unsupported struct**: Throws AMCDecodeException (See Custom Struct Support above). 121 | 2. **Mismatch between -AMCKeysForDictionaryRepresentation & Dictionary Representation Keys**: No exceptions gets thrown. Only intersect of keys in 122 | dictionary representation & -AMCKeysForDictionaryRepresentation are used to set values for decoding object's fields. So always check for neccessery fields in your -initWithDictionaryRepresentation and create them if they are nil. 123 | 3. **Object for Scalar key in Dictionary Representation**: KVC will throw NSInvalidArgumentException i.e. if you're trying to set Object with it's own dictionary representation as simple int. 124 | 4. **Scalar for Object key in Dictionary Representation**: No exception gets thrown. Object will not be set - so your property will still handle nil. 125 | 5. **Object with different class name for Object Key in Dictionary Representation**: No exception gets thrown. I.e. it's possible to set Foo instance for Bar class property with AMC. Their own properties can be set with AMC or remain nil. Do [self.foo isKindOfClass: [Foo class]] checks in -initWithDictinoaryRepresentation: after calling super if it's necessary. 126 | 127 | AMC_NO_THROW 128 | ------------------ 129 | 130 | You can define AMC_NO_THROW to disable exceptions throw by following methods: 131 | 132 | * +objectWithDictionaryRepresentation: 133 | * -initWithDictionaryRepresentation: 134 | * -loadValueForKey:fromDictionaryRepresentation: 135 | * -dictionaryRepresentation 136 | 137 | With AMC_NO_THROW defined they will simply return nil and/or do nothing instead. 138 | -AMCDecodeStructFromString:withName: & -AMCEncodeStructWithValue:withName: can 139 | throw exceptions even if AMC_NO_THROW is defined. Don't catch any exceptions in 140 | your reimplementations of these methods - you don't need to call them directly, so AMC 141 | will catch their exceptions for you. 142 | 143 | License 144 | ================== 145 | AMC is licensed under terms & conditions of MIT License. 146 | http://www.opensource.org/licenses/mit-license.php 147 | 148 | Copyright 2011 Stepan Generalov. 149 | 150 | Permission is hereby granted, free of charge, to any person obtaining a copy 151 | of this software and associated documentation files (the "Software"), to deal 152 | in the Software without restriction, including without limitation the rights 153 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 154 | copies of the Software, and to permit persons to whom the Software is 155 | furnished to do so, subject to the following conditions: 156 | 157 | The above copyright notice and this permission notice shall be included in 158 | all copies or substantial portions of the Software. 159 | 160 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 161 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 162 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 163 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 164 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 165 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 166 | THE SOFTWARE. 167 | -------------------------------------------------------------------------------- /SupportingFiles/SupportingFiles-Mac/AutomagicCoding-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | StepanGeneralov.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSMinimumSystemVersion 26 | ${MACOSX_DEPLOYMENT_TARGET} 27 | NSHumanReadableCopyright 28 | Copyright © 2011 Stepan Generalov. 29 | NSMainNibFile 30 | MainMenu 31 | NSPrincipalClass 32 | NSApplication 33 | 34 | 35 | -------------------------------------------------------------------------------- /SupportingFiles/SupportingFiles-Mac/AutomagicCoding-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'AutoMagicCoding' target in the 'AutoMagicCoding' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #endif 8 | -------------------------------------------------------------------------------- /SupportingFiles/SupportingFiles-Mac/AutomagicCodingAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AutoMagicCodingAppDelegate.h 3 | // AutoMagicCoding 4 | // 5 | // 31.08.11. 6 | // Copyright 2011 Stepan Generalov. 7 | // 8 | 9 | #import 10 | 11 | @interface AutoMagicCodingAppDelegate : NSObject { 12 | NSWindow *window; 13 | } 14 | 15 | @property (assign) IBOutlet NSWindow *window; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /SupportingFiles/SupportingFiles-Mac/AutomagicCodingAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AutoMagicCodingAppDelegate.m 3 | // AutoMagicCoding 4 | // 5 | // 31.08.11. 6 | // Copyright 2011 Stepan Generalov. 7 | // 8 | 9 | #import "AutoMagicCodingAppDelegate.h" 10 | 11 | @implementation AutoMagicCodingAppDelegate 12 | 13 | @synthesize window; 14 | 15 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification 16 | { 17 | } 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /SupportingFiles/SupportingFiles-Mac/en.lproj/Credits.rtf: -------------------------------------------------------------------------------- 1 | {\rtf0\ansi{\fonttbl\f0\fswiss Helvetica;} 2 | {\colortbl;\red255\green255\blue255;} 3 | \paperw9840\paperh8400 4 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural 5 | 6 | \f0\b\fs24 \cf0 Engineering: 7 | \b0 \ 8 | Some people\ 9 | \ 10 | 11 | \b Human Interface Design: 12 | \b0 \ 13 | Some other people\ 14 | \ 15 | 16 | \b Testing: 17 | \b0 \ 18 | Hopefully not nobody\ 19 | \ 20 | 21 | \b Documentation: 22 | \b0 \ 23 | Whoever\ 24 | \ 25 | 26 | \b With special thanks to: 27 | \b0 \ 28 | Mom\ 29 | } 30 | -------------------------------------------------------------------------------- /SupportingFiles/SupportingFiles-Mac/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /SupportingFiles/SupportingFiles-Mac/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // AutoMagicCoding 4 | // 5 | // 31.08.11. 6 | // Copyright 2011 Stepan Generalov. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, char *argv[]) 12 | { 13 | return NSApplicationMain(argc, (const char **)argv); 14 | } 15 | -------------------------------------------------------------------------------- /SupportingFiles/SupportingFiles-Tests-Mac/AutomagicCodingTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | StepanGeneralov.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /SupportingFiles/SupportingFiles-Tests-Mac/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /SupportingFiles/SupportingFiles-Tests-iOS/AutoMagicCoding-iOSTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | StepanGeneralov.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /SupportingFiles/SupportingFiles-Tests-iOS/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /SupportingFiles/SupportingFiles-iOS/AutoMagicCoding-iOS-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIconFile 12 | 13 | CFBundleIdentifier 14 | StepanGeneralov.${PRODUCT_NAME:rfc1034identifier} 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | ${PRODUCT_NAME} 19 | CFBundlePackageType 20 | APPL 21 | CFBundleShortVersionString 22 | 1.0 23 | CFBundleSignature 24 | ???? 25 | CFBundleVersion 26 | 1.0 27 | LSRequiresIPhoneOS 28 | 29 | NSMainNibFile 30 | MainWindow_iPhone 31 | NSMainNibFile~ipad 32 | MainWindow_iPad 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /SupportingFiles/SupportingFiles-iOS/AutoMagicCoding-iOS-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'AutoMagicCoding-iOS' target in the 'AutoMagicCoding-iOS' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_3_0 8 | #warning "This project uses features only available in iPhone SDK 3.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #endif 15 | -------------------------------------------------------------------------------- /SupportingFiles/SupportingFiles-iOS/AutoMagicCoding_iOSAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AutoMagicCoding_iOSAppDelegate.h 3 | // AutoMagicCoding-iOS 4 | // 5 | // 02.09.11. 6 | // Copyright 2011 Stepan Generalov. 7 | // 8 | 9 | #import 10 | 11 | @interface AutoMagicCoding_iOSAppDelegate : NSObject 12 | 13 | @property (nonatomic, retain) IBOutlet UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /SupportingFiles/SupportingFiles-iOS/AutoMagicCoding_iOSAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AutoMagicCoding_iOSAppDelegate.m 3 | // AutoMagicCoding-iOS 4 | // 5 | // 02.09.11. 6 | // Copyright 2011 Stepan Generalov. 7 | // 8 | 9 | #import "AutoMagicCoding_iOSAppDelegate.h" 10 | 11 | @implementation AutoMagicCoding_iOSAppDelegate 12 | 13 | @synthesize window = _window; 14 | 15 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 16 | { 17 | // Override point for customization after application launch. 18 | [self.window makeKeyAndVisible]; 19 | return YES; 20 | } 21 | 22 | - (void)applicationWillResignActive:(UIApplication *)application 23 | { 24 | /* 25 | Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 26 | Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 27 | */ 28 | } 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application 31 | { 32 | /* 33 | Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 34 | If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 35 | */ 36 | } 37 | 38 | - (void)applicationWillEnterForeground:(UIApplication *)application 39 | { 40 | /* 41 | Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 42 | */ 43 | } 44 | 45 | - (void)applicationDidBecomeActive:(UIApplication *)application 46 | { 47 | /* 48 | Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 49 | */ 50 | } 51 | 52 | - (void)applicationWillTerminate:(UIApplication *)application 53 | { 54 | /* 55 | Called when the application is about to terminate. 56 | Save data if appropriate. 57 | See also applicationDidEnterBackground:. 58 | */ 59 | } 60 | 61 | - (void)dealloc 62 | { 63 | [_window release]; 64 | [super dealloc]; 65 | } 66 | 67 | @end 68 | -------------------------------------------------------------------------------- /SupportingFiles/SupportingFiles-iOS/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /SupportingFiles/SupportingFiles-iOS/iPad/AutoMagicCoding_iOSAppDelegate_iPad.h: -------------------------------------------------------------------------------- 1 | // 2 | // AutoMagicCoding_iOSAppDelegate_iPad.h 3 | // AutoMagicCoding-iOS 4 | // 5 | // 02.09.11. 6 | // Copyright 2011 Stepan Generalov. 7 | // 8 | 9 | #import "AutoMagicCoding_iOSAppDelegate.h" 10 | 11 | @interface AutoMagicCoding_iOSAppDelegate_iPad : AutoMagicCoding_iOSAppDelegate 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /SupportingFiles/SupportingFiles-iOS/iPad/AutoMagicCoding_iOSAppDelegate_iPad.m: -------------------------------------------------------------------------------- 1 | // 2 | // AutoMagicCoding_iOSAppDelegate_iPad.m 3 | // AutoMagicCoding-iOS 4 | // 5 | // 02.09.11. 6 | // Copyright 2011 Stepan Generalov. 7 | // 8 | 9 | #import "AutoMagicCoding_iOSAppDelegate_iPad.h" 10 | 11 | @implementation AutoMagicCoding_iOSAppDelegate_iPad 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /SupportingFiles/SupportingFiles-iOS/iPad/en.lproj/MainWindow_iPad.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1024 5 | 10D573 6 | 786 7 | 1038.29 8 | 460.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 112 12 | 13 | 14 | YES 15 | 16 | 17 | 18 | YES 19 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 20 | 21 | 22 | YES 23 | 24 | YES 25 | 26 | 27 | YES 28 | 29 | 30 | 31 | YES 32 | 33 | IBFilesOwner 34 | IBIPadFramework 35 | 36 | 37 | IBFirstResponder 38 | IBIPadFramework 39 | 40 | 41 | 42 | 292 43 | 44 | YES 45 | 46 | 47 | 301 48 | {{284, 501}, {200, 22}} 49 | 50 | NO 51 | YES 52 | 7 53 | NO 54 | IBIPadFramework 55 | My Universal App on iPad 56 | 57 | 1 58 | MCAwIDAAA 59 | 60 | 61 | 1 62 | 10 63 | 64 | 65 | {768, 1024} 66 | 67 | 68 | 1 69 | MSAxIDEAA 70 | 71 | NO 72 | NO 73 | 74 | 2 75 | 76 | IBIPadFramework 77 | YES 78 | 79 | 80 | IBIPadFramework 81 | 82 | 83 | 84 | 85 | YES 86 | 87 | 88 | window 89 | 90 | 91 | 92 | 7 93 | 94 | 95 | 96 | delegate 97 | 98 | 99 | 100 | 8 101 | 102 | 103 | 104 | 105 | YES 106 | 107 | 0 108 | 109 | 110 | 111 | 112 | 113 | -1 114 | 115 | 116 | File's Owner 117 | 118 | 119 | -2 120 | 121 | 122 | 123 | 124 | 2 125 | 126 | 127 | YES 128 | 129 | 130 | 131 | 132 | 133 | 6 134 | 135 | 136 | 137 | 138 | 11 139 | 140 | 141 | 142 | 143 | 144 | 145 | YES 146 | 147 | YES 148 | -1.CustomClassName 149 | -2.CustomClassName 150 | 11.IBPluginDependency 151 | 2.IBEditorWindowLastContentRect 152 | 2.IBPluginDependency 153 | 6.CustomClassName 154 | 6.IBPluginDependency 155 | 156 | 157 | YES 158 | UIApplication 159 | UIResponder 160 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 161 | {{202, 84}, {783, 772}} 162 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 163 | AutoMagicCoding_iOSAppDelegate_iPad 164 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 165 | 166 | 167 | 168 | YES 169 | 170 | 171 | YES 172 | 173 | 174 | 175 | 176 | YES 177 | 178 | 179 | YES 180 | 181 | 182 | 183 | 11 184 | 185 | 186 | 187 | YES 188 | 189 | AutoMagicCoding_iOSAppDelegate 190 | NSObject 191 | 192 | window 193 | UIWindow 194 | 195 | 196 | window 197 | 198 | window 199 | UIWindow 200 | 201 | 202 | 203 | IBProjectSource 204 | Shared/AutoMagicCoding_iOSAppDelegate.h 205 | 206 | 207 | 208 | AutoMagicCoding_iOSAppDelegate_iPad 209 | AutoMagicCoding_iOSAppDelegate 210 | 211 | IBProjectSource 212 | iPad/AutoMagicCoding_iOSAppDelegate_iPad.h 213 | 214 | 215 | 216 | 217 | YES 218 | 219 | NSObject 220 | 221 | IBFrameworkSource 222 | Foundation.framework/Headers/NSError.h 223 | 224 | 225 | 226 | NSObject 227 | 228 | IBFrameworkSource 229 | Foundation.framework/Headers/NSFileManager.h 230 | 231 | 232 | 233 | NSObject 234 | 235 | IBFrameworkSource 236 | Foundation.framework/Headers/NSKeyValueCoding.h 237 | 238 | 239 | 240 | NSObject 241 | 242 | IBFrameworkSource 243 | Foundation.framework/Headers/NSKeyValueObserving.h 244 | 245 | 246 | 247 | NSObject 248 | 249 | IBFrameworkSource 250 | Foundation.framework/Headers/NSKeyedArchiver.h 251 | 252 | 253 | 254 | NSObject 255 | 256 | IBFrameworkSource 257 | Foundation.framework/Headers/NSObject.h 258 | 259 | 260 | 261 | NSObject 262 | 263 | IBFrameworkSource 264 | Foundation.framework/Headers/NSRunLoop.h 265 | 266 | 267 | 268 | NSObject 269 | 270 | IBFrameworkSource 271 | Foundation.framework/Headers/NSThread.h 272 | 273 | 274 | 275 | NSObject 276 | 277 | IBFrameworkSource 278 | Foundation.framework/Headers/NSURL.h 279 | 280 | 281 | 282 | NSObject 283 | 284 | IBFrameworkSource 285 | Foundation.framework/Headers/NSURLConnection.h 286 | 287 | 288 | 289 | NSObject 290 | 291 | IBFrameworkSource 292 | UIKit.framework/Headers/UIAccessibility.h 293 | 294 | 295 | 296 | NSObject 297 | 298 | IBFrameworkSource 299 | UIKit.framework/Headers/UINibLoading.h 300 | 301 | 302 | 303 | NSObject 304 | 305 | IBFrameworkSource 306 | UIKit.framework/Headers/UIResponder.h 307 | 308 | 309 | 310 | UIApplication 311 | UIResponder 312 | 313 | IBFrameworkSource 314 | UIKit.framework/Headers/UIApplication.h 315 | 316 | 317 | 318 | UIResponder 319 | NSObject 320 | 321 | 322 | 323 | UIView 324 | 325 | IBFrameworkSource 326 | UIKit.framework/Headers/UITextField.h 327 | 328 | 329 | 330 | UIView 331 | UIResponder 332 | 333 | IBFrameworkSource 334 | UIKit.framework/Headers/UIView.h 335 | 336 | 337 | 338 | UIWindow 339 | UIView 340 | 341 | IBFrameworkSource 342 | UIKit.framework/Headers/UIWindow.h 343 | 344 | 345 | 346 | 347 | 0 348 | IBIPadFramework 349 | 350 | com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS 351 | 352 | 353 | 354 | com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 355 | 356 | 357 | YES 358 | ../AutoMagicCoding-iOS.xcodeproj 359 | 3 360 | 112 361 | 362 | 363 | -------------------------------------------------------------------------------- /SupportingFiles/SupportingFiles-iOS/iPhone/AutoMagicCoding_iOSAppDelegate_iPhone.h: -------------------------------------------------------------------------------- 1 | // 2 | // AutoMagicCoding_iOSAppDelegate_iPhone.h 3 | // AutoMagicCoding-iOS 4 | // 5 | // 02.09.11. 6 | // Copyright 2011 Stepan Generalov. 7 | // 8 | 9 | #import "AutoMagicCoding_iOSAppDelegate.h" 10 | 11 | @interface AutoMagicCoding_iOSAppDelegate_iPhone : AutoMagicCoding_iOSAppDelegate 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /SupportingFiles/SupportingFiles-iOS/iPhone/AutoMagicCoding_iOSAppDelegate_iPhone.m: -------------------------------------------------------------------------------- 1 | // 2 | // AutoMagicCoding_iOSAppDelegate_iPhone.m 3 | // AutoMagicCoding-iOS 4 | // 5 | // 02.09.11. 6 | // Copyright 2011 Stepan Generalov. 7 | // 8 | 9 | #import "AutoMagicCoding_iOSAppDelegate_iPhone.h" 10 | 11 | @implementation AutoMagicCoding_iOSAppDelegate_iPhone 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /SupportingFiles/SupportingFiles-iOS/iPhone/en.lproj/MainWindow_iPhone.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1024 5 | 10D573 6 | 786 7 | 1038.29 8 | 460.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 112 12 | 13 | 14 | YES 15 | 16 | 17 | 18 | YES 19 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 20 | 21 | 22 | YES 23 | 24 | YES 25 | 26 | 27 | YES 28 | 29 | 30 | 31 | YES 32 | 33 | IBFilesOwner 34 | IBCocoaTouchFramework 35 | 36 | 37 | IBFirstResponder 38 | IBCocoaTouchFramework 39 | 40 | 41 | IBCocoaTouchFramework 42 | 43 | 44 | 45 | 1316 46 | 47 | YES 48 | 49 | 50 | 1325 51 | {{51, 229}, {218, 22}} 52 | 53 | NO 54 | YES 55 | 7 56 | NO 57 | IBCocoaTouchFramework 58 | My Universal App on iPhone 59 | 60 | 1 61 | MCAwIDAAA 62 | 63 | 64 | 1 65 | 10 66 | 67 | 68 | 69 | {320, 480} 70 | 71 | 72 | 1 73 | MSAxIDEAA 74 | 75 | NO 76 | NO 77 | 78 | IBCocoaTouchFramework 79 | YES 80 | 81 | 82 | 83 | 84 | YES 85 | 86 | 87 | delegate 88 | 89 | 90 | 91 | 5 92 | 93 | 94 | 95 | window 96 | 97 | 98 | 99 | 6 100 | 101 | 102 | 103 | 104 | YES 105 | 106 | 0 107 | 108 | 109 | 110 | 111 | 112 | 2 113 | 114 | 115 | YES 116 | 117 | 118 | 119 | 120 | 121 | -1 122 | 123 | 124 | File's Owner 125 | 126 | 127 | 4 128 | 129 | 130 | App Delegate 131 | 132 | 133 | -2 134 | 135 | 136 | 137 | 138 | 8 139 | 140 | 141 | 142 | 143 | 144 | 145 | YES 146 | 147 | YES 148 | -1.CustomClassName 149 | -2.CustomClassName 150 | 2.IBAttributePlaceholdersKey 151 | 2.IBEditorWindowLastContentRect 152 | 2.IBPluginDependency 153 | 2.UIWindow.visibleAtLaunch 154 | 4.CustomClassName 155 | 4.IBPluginDependency 156 | 8.IBPluginDependency 157 | 158 | 159 | YES 160 | UIApplication 161 | UIResponder 162 | 163 | YES 164 | 165 | 166 | YES 167 | 168 | 169 | {{520, 376}, {320, 480}} 170 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 171 | 172 | AutoMagicCoding_iOSAppDelegate_iPhone 173 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 174 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 175 | 176 | 177 | 178 | YES 179 | 180 | 181 | YES 182 | 183 | 184 | 185 | 186 | YES 187 | 188 | 189 | YES 190 | 191 | 192 | 193 | 8 194 | 195 | 196 | 197 | YES 198 | 199 | AutoMagicCoding_iOSAppDelegate 200 | NSObject 201 | 202 | window 203 | UIWindow 204 | 205 | 206 | window 207 | 208 | window 209 | UIWindow 210 | 211 | 212 | 213 | IBProjectSource 214 | Shared/AutoMagicCoding_iOSAppDelegate.h 215 | 216 | 217 | 218 | AutoMagicCoding_iOSAppDelegate_iPhone 219 | AutoMagicCoding_iOSAppDelegate 220 | 221 | IBProjectSource 222 | iPhone/AutoMagicCoding_iOSAppDelegate_iPhone.h 223 | 224 | 225 | 226 | 227 | YES 228 | 229 | NSObject 230 | 231 | IBFrameworkSource 232 | Foundation.framework/Headers/NSError.h 233 | 234 | 235 | 236 | NSObject 237 | 238 | IBFrameworkSource 239 | Foundation.framework/Headers/NSFileManager.h 240 | 241 | 242 | 243 | NSObject 244 | 245 | IBFrameworkSource 246 | Foundation.framework/Headers/NSKeyValueCoding.h 247 | 248 | 249 | 250 | NSObject 251 | 252 | IBFrameworkSource 253 | Foundation.framework/Headers/NSKeyValueObserving.h 254 | 255 | 256 | 257 | NSObject 258 | 259 | IBFrameworkSource 260 | Foundation.framework/Headers/NSKeyedArchiver.h 261 | 262 | 263 | 264 | NSObject 265 | 266 | IBFrameworkSource 267 | Foundation.framework/Headers/NSObject.h 268 | 269 | 270 | 271 | NSObject 272 | 273 | IBFrameworkSource 274 | Foundation.framework/Headers/NSRunLoop.h 275 | 276 | 277 | 278 | NSObject 279 | 280 | IBFrameworkSource 281 | Foundation.framework/Headers/NSThread.h 282 | 283 | 284 | 285 | NSObject 286 | 287 | IBFrameworkSource 288 | Foundation.framework/Headers/NSURL.h 289 | 290 | 291 | 292 | NSObject 293 | 294 | IBFrameworkSource 295 | Foundation.framework/Headers/NSURLConnection.h 296 | 297 | 298 | 299 | NSObject 300 | 301 | IBFrameworkSource 302 | UIKit.framework/Headers/UIAccessibility.h 303 | 304 | 305 | 306 | NSObject 307 | 308 | IBFrameworkSource 309 | UIKit.framework/Headers/UINibLoading.h 310 | 311 | 312 | 313 | NSObject 314 | 315 | IBFrameworkSource 316 | UIKit.framework/Headers/UIResponder.h 317 | 318 | 319 | 320 | UIApplication 321 | UIResponder 322 | 323 | IBFrameworkSource 324 | UIKit.framework/Headers/UIApplication.h 325 | 326 | 327 | 328 | UIResponder 329 | NSObject 330 | 331 | 332 | 333 | UIView 334 | 335 | IBFrameworkSource 336 | UIKit.framework/Headers/UITextField.h 337 | 338 | 339 | 340 | UIView 341 | UIResponder 342 | 343 | IBFrameworkSource 344 | UIKit.framework/Headers/UIView.h 345 | 346 | 347 | 348 | UIWindow 349 | UIView 350 | 351 | IBFrameworkSource 352 | UIKit.framework/Headers/UIWindow.h 353 | 354 | 355 | 356 | 357 | 0 358 | IBCocoaTouchFramework 359 | 360 | com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS 361 | 362 | 363 | 364 | com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 365 | 366 | 367 | YES 368 | ../AutoMagicCoding-iOS.xcodeproj 369 | 3 370 | 112 371 | 372 | 373 | -------------------------------------------------------------------------------- /SupportingFiles/SupportingFiles-iOS/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // AutoMagicCoding-iOS 4 | // 5 | // 02.09.11. 6 | // Copyright 2011 Stepan Generalov. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, char *argv[]) 12 | { 13 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 14 | int retVal = UIApplicationMain(argc, argv, nil, nil); 15 | [pool release]; 16 | return retVal; 17 | } 18 | -------------------------------------------------------------------------------- /Tests/AMCCollectionsTest.h: -------------------------------------------------------------------------------- 1 | // 2 | // AMCCollectionsTest.h 3 | // AutoMagicCoding 4 | // 5 | // 02.09.11. 6 | // Copyright 2011 Stepan Generalov. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import 27 | #import "FooWithCollections.h" 28 | #import "AMCTest.h" 29 | 30 | @interface AMCCollectionsTest : AMCTest 31 | { 32 | FooWithCollections *_fooWithCollections; 33 | } 34 | 35 | @property(readwrite, retain) FooWithCollections *fooWithCollections; 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /Tests/AMCExceptionsTest.h: -------------------------------------------------------------------------------- 1 | // 2 | // AMCExceptionsTest.h 3 | // AutoMagicCoding 4 | // 5 | // 03.12.11. 6 | // Copyright 2011 Stepan Generalov. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import 27 | #import "AMCTest.h" 28 | 29 | @interface AMCExceptionsTest : AMCTest 30 | 31 | @end 32 | 33 | #pragma mark Unsupported Custom Struct 34 | 35 | struct UnsupportedByAMCStruct { 36 | int i; 37 | int g; 38 | }; 39 | typedef struct UnsupportedByAMCStruct UnsupportedByAMCStruct; 40 | 41 | @interface BadClass : NSObject { 42 | 43 | UnsupportedByAMCStruct _struct; 44 | } 45 | @end 46 | 47 | #pragma mark Object with bad AMCKeysForDictionaryRepresentation 48 | 49 | @interface Foobar : NSObject { 50 | } 51 | @end -------------------------------------------------------------------------------- /Tests/AMCExceptionsTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // AMCExceptionsTest.h 3 | // AutoMagicCoding 4 | // 5 | // 03.12.11. 6 | // Copyright 2011 Stepan Generalov. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import "AMCExceptionsTest.h" 27 | #import "NSObject+AutoMagicCoding.h" 28 | #import "Bar.h" 29 | #import "Foo.h" 30 | 31 | @implementation AMCExceptionsTest 32 | 33 | // BadClass have UnsupportedByAMCStruct ivar. 34 | // -dictionaryRepresentation should crash with AMCEncodeException 35 | - (void)testEncodeUnsupportedStructCrash 36 | { 37 | BadClass *object = [BadClass new]; 38 | 39 | #ifdef AMC_NO_THROW 40 | 41 | STAssertTrueNoThrow(nil == [object dictionaryRepresentation], @"On AMC_NO_THROW AMC should return nil instead of throwing exceptions!"); 42 | 43 | #else 44 | 45 | STAssertThrowsSpecificNamed([object dictionaryRepresentation] , NSException, AMCEncodeException, @""); 46 | 47 | #endif 48 | } 49 | 50 | // BadClass have UnsupportedByAMCStruct ivar, that's name is added to 51 | // AMCKeysForDictionaryRepresentation. 52 | // +objectWithDictionaryRepresentation should crash with AMCDecodeException 53 | - (void)testDecodeUnsupportedStructCrash 54 | { 55 | // Prepare dictionary representation manually. 56 | NSDictionary *dict = [NSDictionary dictionaryWithObjects: 57 | [NSArray arrayWithObjects: @"BadClass", @"i=5", nil ] 58 | forKeys: 59 | [NSArray arrayWithObjects: @"class", @"struct", nil] 60 | ]; 61 | 62 | #ifdef AMC_NO_THROW 63 | 64 | STAssertTrueNoThrow( nil == [NSObject objectWithDictionaryRepresentation: dict], @"On AMC_NO_THROW AMC should return nil instead of throwing exceptions!"); 65 | 66 | #else 67 | 68 | // Crash on decode. 69 | STAssertThrowsSpecificNamed([NSObject objectWithDictionaryRepresentation: dict] , NSException, AMCDecodeException,@""); 70 | 71 | #endif 72 | } 73 | 74 | // Each time when AMC creates dictionary representation of an object - it uses 75 | // -AMCKeysForDictionaryRepresentation return value as an array of keys. 76 | // AMC Uses KVC's -valueForKey: method to retreive values. 77 | // If it's impossible to get value - KVC throws NSUnkownKeyException 78 | - (void) testEncodeWrongKeyInAMCKeysCrash 79 | { 80 | Foobar *object = [Foobar new]; 81 | 82 | #ifdef AMC_NO_THROW 83 | 84 | STAssertTrueNoThrow( nil == [object dictionaryRepresentation], @"On AMC_NO_THROW AMC should return nil instead of throwing exceptions!"); 85 | 86 | #else 87 | 88 | STAssertThrowsSpecificNamed([object dictionaryRepresentation], NSException, @"NSUnknownKeyException", @""); 89 | 90 | #endif 91 | } 92 | 93 | 94 | // Each time when object is created from dictionary representation - it uses 95 | // className to create an instance, and then uses 96 | // -AMCKeysForDictionaryRepresentation return value as an array of keys. 97 | // If there's no such key in given dict - AMC will skip it & 98 | // no crash will occur. 99 | - (void) testDecodeUnnecessaryKeyInDict 100 | { 101 | // Prepare dictionary representation manually. 102 | NSDictionary *dict = [[NSDictionary dictionaryWithObjects: [NSArray arrayWithObjects: @"Foobar", @"wrongString", nil] 103 | forKeys: [NSArray arrayWithObjects: kAMCDictionaryKeyClassName, @"wrongKeyThatDoesntExist", nil] 104 | ] retain]; 105 | 106 | // Don't crash on decode. 107 | STAssertNoThrow([[[NSObject objectWithDictionaryRepresentation: dict] retain] autorelease], @""); 108 | } 109 | 110 | // Changed Foo's dictionaryRepresentation to have Object dictionaryRepresentation 111 | // in one property instead of simple int value. 112 | // Should crash in KVC's methods with NSInvalidArgumentException 113 | - (void) testDecodeObjectToInt 114 | { 115 | // ===== Prepare Foo instance. ===== 116 | Foo *foo = [[Foo new] autorelease]; 117 | foo.publicBar = [[Bar new] autorelease]; 118 | foo.integerValue = 17; 119 | Bar *privateBarInFoo = [[Bar new]autorelease]; 120 | [foo setValue: privateBarInFoo forKey:@"privateBar"]; 121 | foo.publicBar.someString = @"Some Randooooom String! =)"; 122 | privateBarInFoo.someString = @"Some another random string - this time it's in private bar!"; 123 | 124 | // ===== Save foo's representation in mutable NSDictionary. ===== 125 | NSMutableDictionary *fooDict = [NSMutableDictionary dictionaryWithDictionary: [foo dictionaryRepresentation] ]; 126 | 127 | // ===== Change integerValue representation with Bar representation in dictionary representation. ===== 128 | NSDictionary *newBarDict = [NSDictionary dictionaryWithObjects: [NSArray arrayWithObjects: @"Bar", @"New Bar to set as Int!", nil] 129 | forKeys: [NSArray arrayWithObjects: kAMCDictionaryKeyClassName, @"someString", nil] 130 | ]; 131 | [fooDict setObject: newBarDict forKey:@"integerValue"]; 132 | 133 | #ifdef AMC_NO_THROW 134 | 135 | STAssertTrueNoThrow( nil == [Foo objectWithDictionaryRepresentation: fooDict], @"On AMC_NO_THROW AMC should return nil instead of throwing exceptions!"); 136 | 137 | #else 138 | 139 | // Should crash on decoding from corrupted dictionary representation with NSInvalidArgumentException. 140 | STAssertThrowsSpecificNamed([Foo objectWithDictionaryRepresentation: fooDict], NSException, NSInvalidArgumentException, @""); 141 | 142 | #endif 143 | } 144 | 145 | // Changed Foo's dictionaryRepresentation to have simple intValue in 146 | // one property instead of object's (Bar) dictionaryRepresentation. 147 | // Shouldn't crash, but publicBar should be nil. 148 | - (void) testDecodeIntToObject 149 | { 150 | // ===== Prepare Foo instance. ===== 151 | Foo *foo = [[Foo new] autorelease]; 152 | foo.publicBar = [[Bar new] autorelease]; 153 | foo.integerValue = 17; 154 | Bar *privateBarInFoo = [[Bar new]autorelease]; 155 | [foo setValue: privateBarInFoo forKey:@"privateBar"]; 156 | foo.publicBar.someString = @"Some Randooooom String! =)"; 157 | privateBarInFoo.someString = @"Some another random string - this time it's in private bar!"; 158 | 159 | // ===== Save foo's representation in mutable NSDictionary. ===== 160 | NSMutableDictionary *fooDict = [NSMutableDictionary dictionaryWithDictionary: [foo dictionaryRepresentation] ]; 161 | 162 | // ===== Change publicBar representation with integerValue representation in foo's dictionary ===== 163 | [fooDict setObject: [NSNumber numberWithInt: 19] forKey:@"publicBar"]; 164 | 165 | // Shouldn't crash on decode. 166 | Foo *newFoo = nil; 167 | STAssertNoThrow(newFoo = [Foo objectWithDictionaryRepresentation: fooDict], @""); 168 | 169 | // newFoo shouldn't be nil. 170 | STAssertTrue([newFoo isKindOfClass: [Foo class]], @"foo class should be Foo but it is %@ instead.", [Foo className]); 171 | 172 | // publicBar should be nil. 173 | STAssertNil(newFoo.publicBar, @"publicBar can't init from int representation. It should be nil, but it's %@ instead", newFoo.publicBar ); 174 | 175 | // It shouldn't be NSNumber. 176 | STAssertFalse([newFoo.publicBar isKindOfClass: [NSNumber class]], @"PublicBar is an NSNumber! THIS IS REALLY BAD!!!"); 177 | } 178 | 179 | - (void) testLoadUnnecessaryKeyInDict 180 | { 181 | // Prepare dictionary representation manually. 182 | NSDictionary *dict = [[NSDictionary dictionaryWithObjects: [NSArray arrayWithObjects: @"Foobar", @"wrongString", nil] 183 | forKeys: [NSArray arrayWithObjects: kAMCDictionaryKeyClassName, @"wrongKeyThatDoesntExist", nil] 184 | ] retain]; 185 | 186 | // Create object. 187 | Foobar *foobar = [Foobar alloc]; 188 | 189 | // Load unsupported key - don't crash when AMC_NO_THROW defined, crash in KVC-set when not defined. 190 | 191 | #ifdef AMC_NO_THROW 192 | 193 | STAssertNoThrow([foobar loadValueForKey:@"wrongKeyThatDoesntExist" fromDictionaryRepresentation: dict], @"On AMC_NO_THROW AMC shouldn't throw exceptions in -loadValueForKey:fromDictionaryRepresentation:!"); 194 | #else 195 | 196 | // Should crash on decoding from corrupted dictionary representation with NSInvalidArgumentException. 197 | STAssertThrowsSpecificNamed([foobar loadValueForKey:@"wrongKeyThatDoesntExist" fromDictionaryRepresentation: dict], NSException, @"NSUnknownKeyException", @""); 198 | 199 | #endif 200 | } 201 | 202 | - (void) testLoadNotPresentKey 203 | { 204 | // Prepare dictionary representation without @"wrongKeyThatDoesntExist" key. 205 | NSDictionary *dict = [[NSDictionary dictionaryWithObjects: [NSArray arrayWithObjects: @"Foobar", nil] 206 | forKeys: [NSArray arrayWithObjects: kAMCDictionaryKeyClassName, nil] 207 | ] retain]; 208 | 209 | // Create object. 210 | Foobar *foobar = [Foobar alloc]; 211 | 212 | // Load not present key - nothing happens. 213 | STAssertNoThrow([foobar loadValueForKey:@"wrongKeyThatDoesntExist" fromDictionaryRepresentation: dict], @"On AMC_NO_THROW AMC shouldn't throw exceptions in -loadValueForKey:fromDictionaryRepresentation:!"); 214 | } 215 | 216 | @end 217 | 218 | @implementation BadClass 219 | 220 | // Note: structs can't be just ivars - they must be properties. 221 | // This is needed, because AMC uses property runtime info for getting 222 | // structName; 223 | //@synthesize struct = _struct; 224 | 225 | + (BOOL) AMCEnabled 226 | { 227 | return YES; 228 | } 229 | 230 | - (NSArray *) AMCKeysForDictionaryRepresentation 231 | { 232 | return [NSArray arrayWithObjects: @"struct", nil]; 233 | } 234 | 235 | - (AMCFieldType) AMCFieldTypeForValueWithKey: (NSString *) aKey 236 | { 237 | if ([aKey isEqualToString:@"struct"]) 238 | { 239 | return kAMCFieldTypeStructure; 240 | } 241 | 242 | return [super AMCFieldTypeForValueWithKey: aKey]; 243 | } 244 | 245 | 246 | @end 247 | 248 | @implementation Foobar 249 | 250 | - (NSArray *) AMCKeysForDictionaryRepresentation 251 | { 252 | return [NSArray arrayWithObjects: @"noSuchKey", @"anotherWrongKey", nil]; 253 | } 254 | 255 | @end 256 | -------------------------------------------------------------------------------- /Tests/AMCTest.h: -------------------------------------------------------------------------------- 1 | // 2 | // AMCTest.h 3 | // AutoMagicCoding 4 | // 5 | // 02.09.11. 6 | // Copyright 2011 Stepan Generalov. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import 27 | 28 | @interface AMCTest : SenTestCase 29 | 30 | /** Returns path for testfile, that can be used in many testcases 31 | * uses className prefix and given suffix. 32 | * So the filename will be something like AMCTestSimpleTest.plist 33 | */ 34 | - (NSString *) testFilePathWithSuffix: (NSString *) aSuffix; 35 | 36 | - (BOOL) array: (NSArray *) arr1 isEqualTo: (NSArray *) arr2; 37 | - (BOOL) dict: (NSDictionary *) dict1 isEqualTo: (NSDictionary *) dict2; 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /Tests/AMCTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // AMCTest.m 3 | // AutoMagicCoding 4 | // 5 | // 02.09.11. 6 | // Copyright 2011 Stepan Generalov. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import "AMCTest.h" 27 | #import "NSObject+AutoMagicCoding.h" 28 | 29 | @implementation AMCTest 30 | 31 | - (void)setUp 32 | { 33 | [super setUp]; 34 | 35 | // Set-up code here. 36 | } 37 | 38 | - (NSString *) testFilePathWithSuffix: (NSString *) aSuffix 39 | { 40 | if (!aSuffix) 41 | aSuffix = @""; 42 | 43 | NSString *filename = [NSString stringWithFormat:@"%@%@.plist", [self className], aSuffix ]; 44 | 45 | NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 46 | NSString *documentsDirectory = [paths objectAtIndex:0]; 47 | NSString *fullPath = [documentsDirectory stringByAppendingPathComponent: filename ]; 48 | return fullPath; 49 | } 50 | 51 | - (void)tearDown 52 | { 53 | // Tear-down code here. 54 | 55 | [super tearDown]; 56 | } 57 | 58 | - (BOOL) array: (NSArray *) arr1 isEqualTo: (NSArray *) arr2 59 | { 60 | if (!arr1 || !arr2) 61 | return NO; 62 | 63 | if ([arr1 count] != [arr2 count]) 64 | return NO; 65 | 66 | for (NSUInteger i = 0; i < [arr1 count]; ++i) 67 | if (![[arr1 objectAtIndex: i] isEqual: [arr2 objectAtIndex:i] ] ) 68 | return NO; 69 | 70 | return YES; 71 | } 72 | 73 | - (BOOL) dict: (NSDictionary *) dict1 isEqualTo: (NSDictionary *) dict2 74 | { 75 | if (!dict1 || !dict2) 76 | return NO; 77 | 78 | if ([dict1 count] != [dict2 count]) 79 | return NO; 80 | 81 | for (NSString *key in dict1) 82 | { 83 | id value1 = [dict1 objectForKey: key]; 84 | id value2 = [dict2 objectForKey: key]; 85 | if ( ![value1 isEqual: value2] ) 86 | return NO; 87 | } 88 | 89 | return YES; 90 | } 91 | 92 | @end 93 | -------------------------------------------------------------------------------- /Tests/AMCTestSimple.h: -------------------------------------------------------------------------------- 1 | // 2 | // AMCTestSimple.h 3 | // AutoMagicCodingTests 4 | // 5 | // 31.08.11. 6 | // Copyright 2011 Stepan Generalov. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import 27 | #import "AMCTest.h" 28 | 29 | @class Foo; 30 | @interface AMCTestSimple : AMCTest 31 | { 32 | Foo *_foo; 33 | } 34 | @property(readwrite, retain) Foo *foo; 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /Tests/AMCTestSimple.m: -------------------------------------------------------------------------------- 1 | // 2 | // AMCTestSimple.m 3 | // AutoMagicCodingTests 4 | // 5 | // 31.08.11. 6 | // Copyright 2011 Stepan Generalov. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import "AMCTestSimple.h" 27 | #import "Foo.h" 28 | #import "Bar.h" 29 | #import "NSObject+AutoMagicCoding.h" 30 | #import "FooWithSctructs.h" 31 | 32 | #ifdef __MAC_OS_X_VERSION_MAX_ALLOWED 33 | #define NSStringFromCGRect(X) NSStringFromRect(NSRectFromCGRect(X)) 34 | #endif 35 | 36 | @implementation AMCTestSimple 37 | @synthesize foo = _foo; 38 | 39 | - (void)setUp 40 | { 41 | [super setUp]; 42 | 43 | // Prepare Foo class - that we will serialize & deserialize in-memory. 44 | Foo *foo = [[Foo new] autorelease]; 45 | foo.publicBar = [[Bar new] autorelease]; 46 | foo.integerValue = 17; 47 | Bar *privateBarInFoo = [[Bar new]autorelease]; 48 | [foo setValue: privateBarInFoo forKey:@"privateBar"]; 49 | 50 | // Prepare inside bar objects in Foo. 51 | foo.publicBar.someString = @"Some Randooooom String! =)"; 52 | privateBarInFoo.someString = @"Some another random string - this time it's int private bar!"; 53 | 54 | // Retain Foo. 55 | self.foo = foo; 56 | } 57 | 58 | - (void)tearDown 59 | { 60 | // Release Foo, 61 | self.foo = nil; 62 | 63 | [super tearDown]; 64 | } 65 | 66 | - (void) testInMemory 67 | { 68 | // Save object representation in NSDictionary. 69 | NSDictionary *fooDict = [self.foo dictionaryRepresentation]; 70 | 71 | // Create new object from that dictionary. 72 | Foo *newFoo = [[Foo objectWithDictionaryRepresentation: fooDict] retain]; 73 | 74 | // Test Foo 75 | STAssertNotNil(newFoo, @"newFoo failed to create."); 76 | 77 | if (![[newFoo className] isEqualToString: [Foo className]]) 78 | STFail(@"newFoo should be Foo!"); 79 | STAssertTrue( [newFoo isMemberOfClass: [Foo class]], @"isMemberOfClass not working: Foo isn't Foo according to it." ); 80 | 81 | // Test Foo.publicBar 82 | STAssertNotNil(newFoo.publicBar, @"newFoo.publicBar failed to create."); 83 | 84 | if (![[newFoo.publicBar className] isEqualToString: [Bar className]]) 85 | STFail(@"newFoo.publicBar should be Bar!"); 86 | STAssertTrue( [newFoo.publicBar isMemberOfClass: [Bar class]], @"isMemberOfClass not working: Bar isn't Bar according to it." ); 87 | 88 | // Test object equality. 89 | STAssertTrue(newFoo.integerValue == self.foo.integerValue, @"foo.integerValue value corrupted during save/load."); 90 | STAssertTrue([newFoo.publicBar.someString isEqualToString: self.foo.publicBar.someString],@"foo.bar.someString corrupted during save/load."); 91 | 92 | // Test addition to keys - ivars without public properties. 93 | STAssertNotNil([newFoo valueForKey: @"privateBar"], @"newFoo.privateBar failed to create."); 94 | 95 | NSString *oldPrivateString = ((Bar *)[self.foo valueForKey:@"privateBar"]).someString; 96 | NSString *newPrivateString = ((Bar *)[newFoo valueForKey:@"privateBar"]).someString; 97 | STAssertTrue([oldPrivateString isEqualToString: newPrivateString],@"foo.privateBar.someString corrupted during save/load."); 98 | 99 | [newFoo release]; 100 | 101 | } 102 | 103 | - (void) testInFile 104 | { 105 | // Save object representation in PLIST & Create new object from that PLIST. 106 | NSString *path = [self testFilePathWithSuffix:nil]; 107 | NSDictionary *dictRepr =[self.foo dictionaryRepresentation]; 108 | [dictRepr writeToFile: path atomically:YES]; 109 | Foo *newFoo = [[Foo objectWithDictionaryRepresentation: [NSDictionary dictionaryWithContentsOfFile: path]] retain]; 110 | 111 | if (![[NSFileManager defaultManager] fileExistsAtPath: path ]) 112 | STFail(@"Test file with path = %@ not exist! Dictionary representation = %@", path, dictRepr); 113 | 114 | // Test Foo 115 | STAssertNotNil(newFoo, @"newFoo failed to create."); 116 | 117 | if (![[newFoo className] isEqualToString: [Foo className]]) 118 | STFail(@"newFoo should be Foo!"); 119 | STAssertTrue( [newFoo isMemberOfClass: [Foo class]], @"isMemberOfClass not working: Foo isn't Foo according to it." ); 120 | 121 | // Test Foo.publicBar 122 | STAssertNotNil(newFoo.publicBar, @"newFoo.publicBar failed to create."); 123 | 124 | if (![[newFoo.publicBar className] isEqualToString: [Bar className]]) 125 | STFail(@"newFoo.publicBar should be Bar!"); 126 | STAssertTrue( [newFoo.publicBar isMemberOfClass: [Bar class]], @"isMemberOfClass not working: Bar isn't Bar according to it." ); 127 | 128 | // Test object equality. 129 | STAssertTrue(newFoo.integerValue == self.foo.integerValue, @"foo.integerValue value corrupted during save/load."); 130 | STAssertTrue([newFoo.publicBar.someString isEqualToString: self.foo.publicBar.someString],@"foo.bar.someString corrupted during save/load."); 131 | 132 | // Test addition to keys - ivars without public properties. 133 | STAssertNotNil([newFoo valueForKey: @"privateBar"], @"newFoo.privateBar failed to create."); 134 | 135 | NSString *oldPrivateString = ((Bar *)[self.foo valueForKey:@"privateBar"]).someString; 136 | NSString *newPrivateString = ((Bar *)[newFoo valueForKey:@"privateBar"]).someString; 137 | STAssertTrue([oldPrivateString isEqualToString: newPrivateString],@"foo.privateBar.someString corrupted during save/load."); 138 | 139 | [newFoo release]; 140 | } 141 | 142 | - (void) testStructsInFile 143 | { 144 | // Prepare and save Foo in Dict. 145 | FooWithSctructs *foo = [FooWithSctructs new]; 146 | foo.point = CGPointMake(15.0f, 16.0f); 147 | foo.size = CGSizeMake(154.45f, 129.0f); 148 | foo.rect = CGRectMake(39.0f, 235.0f, 1233.09f, 124.0f); 149 | NSDictionary *fooDict = [foo dictionaryRepresentation]; 150 | 151 | // Save object representation in PLIST & Create new object from that PLIST. 152 | NSString *path = [self testFilePathWithSuffix:@"Struct"]; 153 | [fooDict writeToFile: path atomically:YES]; 154 | // Load newFoo from dict 155 | FooWithSctructs *newFoo = [[FooWithSctructs objectWithDictionaryRepresentation: [NSDictionary dictionaryWithContentsOfFile: path]] retain]; 156 | 157 | if (![[NSFileManager defaultManager] fileExistsAtPath: path ]) 158 | STFail(@"Test file with path = %@ not exist! Dictionary representation = %@", path, fooDict); 159 | 160 | // Test Foo 161 | STAssertNotNil(newFoo, @"newFoo failed to create."); 162 | 163 | if (![[newFoo className] isEqualToString: [FooWithSctructs className]]) 164 | STFail(@"newFoo should be FooWithStructs!"); 165 | STAssertTrue( [newFoo isMemberOfClass: [FooWithSctructs class]], @"isMemberOfClass not working: Foo isn't FooWithSctructs according to it." ); 166 | 167 | // Test foo's equality. 168 | STAssertTrue( CGSizeEqualToSize(foo.size, newFoo.size), @"foo.size = {%f, %f} newFoo.size = {%f, %f} ", 169 | foo.size.width, foo.size.height, newFoo.size.width, newFoo.size.height); 170 | STAssertTrue( CGPointEqualToPoint(foo.point, newFoo.point),@"foo.point = {%f, %f} newFoo.point = {%f, %f}", 171 | foo.point.x, foo.point.y, newFoo.point.x, newFoo.point.y); 172 | STAssertTrue( CGRectEqualToRect(foo.rect, newFoo.rect), @"Foo.rect = %@ newFoo.rect = %@", NSStringFromCGRect(foo.rect), NSStringFromCGRect(newFoo.rect) ); 173 | 174 | 175 | // Release foo's. 176 | [foo release]; 177 | [newFoo release]; 178 | } 179 | 180 | - (void) testStructsInMemory 181 | { 182 | // Prepare and save Foo in Dict. 183 | FooWithSctructs *foo = [FooWithSctructs new]; 184 | foo.point = CGPointMake(15.0f, 16.0f); 185 | foo.size = CGSizeMake(154.45f, 129.0f); 186 | foo.rect = CGRectMake(39.0f, 235.0f, 1233.09f, 124.0f); 187 | NSDictionary *fooDict = [foo dictionaryRepresentation]; 188 | 189 | // Load newFoo from dict 190 | FooWithSctructs *newFoo = [[FooWithSctructs objectWithDictionaryRepresentation: fooDict] retain]; 191 | 192 | // Test foo's equality. 193 | STAssertTrue( CGSizeEqualToSize(foo.size, newFoo.size), @"foo.size = {%f, %f} newFoo.size = {%f, %f} ", 194 | foo.size.width, foo.size.height, newFoo.size.width, newFoo.size.height); 195 | STAssertTrue( CGPointEqualToPoint(foo.point, newFoo.point),@"foo.point = {%f, %f} newFoo.point = {%f, %f}", 196 | foo.point.x, foo.point.y, newFoo.point.x, newFoo.point.y); 197 | STAssertTrue( CGRectEqualToRect(foo.rect, newFoo.rect), @"Foo.rect = %@ newFoo.rect = %@", NSStringFromCGRect(foo.rect), NSStringFromCGRect(newFoo.rect) ); 198 | 199 | // Release foo's. 200 | [foo release]; 201 | [newFoo release]; 202 | } 203 | 204 | - (void) testStructTypeDetection 205 | { 206 | FooWithSctructs *foo = [FooWithSctructs new]; 207 | 208 | 209 | objc_property_t propertyPoint = class_getProperty([foo class], [@"point" cStringUsingEncoding:NSUTF8StringEncoding]); 210 | NSString *structNamePoint = AMCPropertyStructName(propertyPoint); 211 | 212 | objc_property_t propertyRect = class_getProperty([foo class], [@"rect" cStringUsingEncoding:NSUTF8StringEncoding]); 213 | NSString *structNameRect = AMCPropertyStructName(propertyRect); 214 | 215 | objc_property_t propertySize = class_getProperty([foo class], [@"size" cStringUsingEncoding:NSUTF8StringEncoding]); 216 | NSString *structNameSize = AMCPropertyStructName(propertySize); 217 | 218 | objc_property_t propertyCustomStruct = class_getProperty([foo class], [@"customStruct" cStringUsingEncoding:NSUTF8StringEncoding]); 219 | NSString *structNameCustom = AMCPropertyStructName(propertyCustomStruct); 220 | 221 | 222 | STAssertTrue([structNamePoint isEqualToString: @"CGPoint"], @"structNamePoint = %@", structNamePoint ); 223 | STAssertTrue([structNameSize isEqualToString: @"CGSize"], @"structNameSize = %@", structNameSize ); 224 | STAssertTrue([structNameRect isEqualToString: @"CGRect"], @"structNameSize = %@", structNameRect ); 225 | STAssertTrue([structNameCustom isEqualToString: @"CustomStruct"], @"structNameCustom = %@", structNameCustom ); 226 | 227 | [foo release]; 228 | } 229 | 230 | - (void) testCustomStructInMemory 231 | { 232 | FooWithSctructs *foo = [FooWithSctructs new]; 233 | foo.point = CGPointMake(15.0f, 16.0f); 234 | foo.size = CGSizeMake(154.45f, 129.0f); 235 | foo.rect = CGRectMake(39.0f, 235.0f, 1233.09f, 124.0f); 236 | 237 | CustomStruct custom; 238 | custom.d = 0.578; 239 | custom.f = 0.3456f; 240 | custom.i = -20; 241 | custom.ui = 55; 242 | foo.customStruct = custom; 243 | 244 | NSDictionary *fooDict = [foo dictionaryRepresentation]; 245 | 246 | 247 | FooWithSctructs *newFoo = [[NSObject objectWithDictionaryRepresentation: fooDict] retain]; 248 | 249 | STAssertTrue(newFoo.customStruct.ui == foo.customStruct.ui, 250 | @"newFoo.customStruct.ui should be %d, but it's %d", foo.customStruct.ui, newFoo.customStruct.ui ); 251 | 252 | STAssertTrue(newFoo.customStruct.d == foo.customStruct.d, 253 | @"newFoo.customStruct.d should be %f, but it's %f", foo.customStruct.d, newFoo.customStruct.d ); 254 | 255 | STAssertTrue(newFoo.customStruct.f == foo.customStruct.f, 256 | @"newFoo.customStruct.f should be %f, but it's %f", foo.customStruct.f, newFoo.customStruct.f ); 257 | 258 | STAssertTrue(newFoo.customStruct.i == foo.customStruct.i, 259 | @"newFoo.customStruct.i should be %d, but it's %d", foo.customStruct.i, newFoo.customStruct.i ); 260 | 261 | [newFoo release]; 262 | } 263 | 264 | - (void) testCustomStructInFile 265 | { 266 | FooWithSctructs *foo = [FooWithSctructs new]; 267 | foo.point = CGPointMake(15.0f, 16.0f); 268 | foo.size = CGSizeMake(154.45f, 129.0f); 269 | foo.rect = CGRectMake(39.0f, 235.0f, 1233.09f, 124.0f); 270 | 271 | CustomStruct custom; 272 | custom.d = 0.578; 273 | custom.f = 0.3456f; 274 | custom.i = -20; 275 | custom.ui = 55; 276 | foo.customStruct = custom; 277 | 278 | NSDictionary *fooDict = [foo dictionaryRepresentation]; 279 | NSString *path = [self testFilePathWithSuffix:@"CustomStruct"]; 280 | [fooDict writeToFile: path atomically:YES]; 281 | 282 | // Load newFoo from dict 283 | FooWithSctructs *newFoo = [[FooWithSctructs objectWithDictionaryRepresentation: [NSDictionary dictionaryWithContentsOfFile: path]] retain]; 284 | 285 | STAssertTrue(newFoo.customStruct.ui == foo.customStruct.ui, 286 | @"newFoo.customStruct.ui should be %d, but it's %d", foo.customStruct.ui, newFoo.customStruct.ui ); 287 | 288 | STAssertTrue(newFoo.customStruct.d == foo.customStruct.d, 289 | @"newFoo.customStruct.d should be %f, but it's %f", foo.customStruct.d, newFoo.customStruct.d ); 290 | 291 | STAssertTrue(newFoo.customStruct.f == foo.customStruct.f, 292 | @"newFoo.customStruct.f should be %f, but it's %f", foo.customStruct.f, newFoo.customStruct.f ); 293 | 294 | STAssertTrue(newFoo.customStruct.i == foo.customStruct.i, 295 | @"newFoo.customStruct.i should be %d, but it's %d", foo.customStruct.i, newFoo.customStruct.i ); 296 | 297 | [newFoo release]; 298 | } 299 | 300 | - (void) testAMCKeysForDictionaryRepresentation 301 | { 302 | // Get AMC Keys. 303 | BarBarBar *barbarbar = [[BarBarBar new] autorelease]; 304 | NSArray *keys = [barbarbar AMCKeysForDictionaryRepresentation]; 305 | 306 | // Test that there's right amount of keys. 307 | NSArray *expectedKeys = [NSArray arrayWithObjects:@"someString", @"someOtherString", @"thirdString", nil]; 308 | STAssertTrue([expectedKeys isEqual: keys], @"ExpectedKeys = %@, but got Keys = %@", expectedKeys, keys); 309 | } 310 | 311 | // No additional ...InFile test needed, cause we use same objects and if other tests 312 | // pass - no need to test can these objects be saved to file or not. 313 | - (void) testLoadValueInMemory 314 | { 315 | // Prepare objects for test with scalar, customObject, struct & customStruct. 316 | Foo *foo = [Foo new]; 317 | foo.publicBar = [Bar new];//< Custom Object 318 | foo.publicBar.someString = @"somestring"; //< Scalar in Custom Object. 319 | foo.integerValue = 15; //< Scalar. 320 | 321 | FooWithSctructs *fooWithStructs = [FooWithSctructs new]; 322 | fooWithStructs.point = CGPointMake(156, 12.5f); // < Struct 323 | CustomStruct custom = {26, 26.1f, 26.2, -9}; 324 | fooWithStructs.customStruct = custom; 325 | 326 | // Prepare dictionary representation of these objects. 327 | NSDictionary *fooRepresentation = [foo dictionaryRepresentation]; 328 | NSDictionary *fooWithStructsRepresentation = [fooWithStructs dictionaryRepresentation]; 329 | 330 | // Alloc new objects, that will be used to test -loadValueForKey:fromDictionaryRepresentation: 331 | Foo *newFoo = [Foo alloc]; 332 | Bar *newBar = [Bar alloc]; //< will test how to create independent custom object from included custom object's representation. 333 | FooWithSctructs *newFooWithStructs = [FooWithSctructs alloc]; 334 | 335 | 336 | // Load one value at time and test that other values aren't loaded. 337 | 338 | // IntegerValue - scalar. 339 | STAssertFalse(newFoo.integerValue == 15, @"newFoo already has integerValue loaded, but it shouldn't!"); 340 | [newFoo loadValueForKey:@"integerValue" fromDictionaryRepresentation: fooRepresentation]; 341 | STAssertTrue(newFoo.integerValue == 15, @"newFoo.integerValue = %d", newFoo.integerValue); 342 | 343 | // PublicBar - Custom Object. 344 | STAssertFalse(newFoo.publicBar != nil, @"Bar shouldn't be loaded at this step!"); 345 | [newFoo loadValueForKey:@"publicBar" fromDictionaryRepresentation:fooRepresentation]; 346 | STAssertNotNil(newFoo.publicBar, @"Bar should be loaded!"); 347 | STAssertTrue([newFoo.publicBar.someString isEqualToString: @"somestring"], @"newFoo.publicBar.someString = %@", newFoo.publicBar.someString); 348 | 349 | // PublicBar as independent object. 350 | STAssertNil(newBar.someString, @"newBar.someString shouldn't be loaded at this step!"); 351 | NSDictionary *publicBarInFooDictionary = [fooRepresentation objectForKey:@"publicBar"]; 352 | [newBar loadValueForKey:@"someString" fromDictionaryRepresentation: publicBarInFooDictionary ]; 353 | STAssertTrue([newBar.someString isEqualToString: @"somestring"], @"newBar.someString = %@", newBar.someString); 354 | 355 | // CGPoint - non-custom structure. 356 | STAssertFalse(CGPointEqualToPoint( newFooWithStructs.point, CGPointMake(156, 12.5f) ) , @"fooWithStructs.point shouldn't be loaded at this step!"); 357 | [newFooWithStructs loadValueForKey:@"point" fromDictionaryRepresentation: fooWithStructsRepresentation]; 358 | STAssertTrue(CGPointEqualToPoint( newFooWithStructs.point, CGPointMake(156, 12.5f) ) , @"fooWithStructs.point failed to load properly!"); 359 | 360 | // CustomStruct. 361 | STAssertFalse(newFooWithStructs.customStruct.ui == 26 , @"fooWithStructs.customStruct shouldn't be loaded at this step!"); 362 | STAssertFalse(newFooWithStructs.customStruct.f == 26.1f , @"fooWithStructs.customStruct shouldn't be loaded at this step!"); 363 | STAssertFalse(newFooWithStructs.customStruct.d == 26.2 , @"fooWithStructs.customStruct shouldn't be loaded at this step!"); 364 | STAssertFalse(newFooWithStructs.customStruct.i == -9 , @"fooWithStructs.customStruct shouldn't be loaded at this step!"); 365 | [newFooWithStructs loadValueForKey:@"customStruct" fromDictionaryRepresentation:fooWithStructsRepresentation]; 366 | 367 | STAssertTrue(newFooWithStructs.customStruct.ui == 26 , @"fooWithStructs.customStruct shouldn't be loaded at this step!"); 368 | STAssertTrue(newFooWithStructs.customStruct.f == 26.1f , @"fooWithStructs.customStruct shouldn't be loaded at this step!"); 369 | STAssertTrue(newFooWithStructs.customStruct.d == 26.2 , @"fooWithStructs.customStruct shouldn't be loaded at this step!"); 370 | STAssertTrue(newFooWithStructs.customStruct.i == -9 , @"fooWithStructs.customStruct shouldn't be loaded at this step!"); 371 | } 372 | 373 | @end 374 | -------------------------------------------------------------------------------- /Tests/ObjectsForTests/Bar.h: -------------------------------------------------------------------------------- 1 | // 2 | // Bar.h 3 | // AutoMagicCoding 4 | // 5 | // 31.08.11. 6 | // Copyright 2011 Stepan Generalov. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import 27 | 28 | @interface Bar : NSObject 29 | { 30 | NSString *_someString; 31 | } 32 | 33 | @property(copy) NSString *someString; 34 | 35 | @end 36 | 37 | @interface BarBar : Bar { 38 | 39 | NSString *_someOtherString; 40 | 41 | } 42 | 43 | @property(copy) NSString *someOtherString; 44 | 45 | @end 46 | 47 | @interface BarBarBar : BarBar { 48 | 49 | NSString *_thirdString; 50 | 51 | } 52 | 53 | @property(copy) NSString *thirdString; 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /Tests/ObjectsForTests/Bar.m: -------------------------------------------------------------------------------- 1 | // 2 | // Bar.m 3 | // AutoMagicCoding 4 | // 5 | // 31.08.11. 6 | // Copyright 2011 Stepan Generalov. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import "Bar.h" 27 | 28 | @implementation Bar 29 | 30 | @synthesize someString = _someString; 31 | 32 | + (BOOL) AMCEnabled 33 | { 34 | return YES; 35 | } 36 | 37 | - (id)init 38 | { 39 | self = [super init]; 40 | if (self) { 41 | // Initialization code here. 42 | } 43 | 44 | return self; 45 | } 46 | 47 | - (BOOL) isEqual:(id)object 48 | { 49 | if ([object isMemberOfClass:[self class]]) 50 | { 51 | Bar *other = (Bar *)object; 52 | if([self.someString isEqualToString: other.someString]) 53 | return YES; 54 | 55 | return NO; 56 | } 57 | 58 | return [super isEqual: object]; 59 | } 60 | 61 | - (NSString *) description 62 | { 63 | return [NSString stringWithFormat:@"%@ someString={%@}",[self class], self.someString]; 64 | } 65 | 66 | @end 67 | 68 | 69 | @implementation BarBar 70 | 71 | @synthesize someOtherString = _someOtherString; 72 | 73 | 74 | @end 75 | 76 | @implementation BarBarBar 77 | 78 | @synthesize thirdString = _thirdString; 79 | 80 | @end 81 | -------------------------------------------------------------------------------- /Tests/ObjectsForTests/CCArray.h: -------------------------------------------------------------------------------- 1 | /* 2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org 3 | * 4 | * Copyright (c) 2010 ForzeField Studios S.L. http://forzefield.com 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | 26 | #import "ccCArray.h" 27 | 28 | 29 | /** A faster alternative of NSArray. 30 | CCArray uses internally a c-array. 31 | @since v0.99.4 32 | */ 33 | 34 | 35 | /** @def CCARRAY_FOREACH 36 | A convience macro to iterate over a CCArray using. It is faster than the "fast enumeration" interface. 37 | @since v0.99.4 38 | */ 39 | 40 | #define CCARRAY_FOREACH(__array__, __object__) \ 41 | if (__array__ && __array__->data->num > 0) \ 42 | for(id *__arr__ = __array__->data->arr, *end = __array__->data->arr + __array__->data->num-1; \ 43 | __arr__ <= end && ((__object__ = *__arr__) != nil || true); \ 44 | __arr__++) 45 | 46 | @interface CCArray : NSObject 47 | { 48 | @public ccArray *data; 49 | } 50 | 51 | + (id) array; 52 | + (id) arrayWithCapacity:(NSUInteger)capacity; 53 | + (id) arrayWithCCArray:(CCArray*)otherArray; 54 | + (id) arrayWithArray:(NSArray*)otherArray; 55 | 56 | 57 | - (id) initWithCapacity:(NSUInteger)capacity; 58 | - (id) initWithCCArray:(CCArray*)otherArray; 59 | - (id) initWithArray:(NSArray*)otherArray; 60 | 61 | 62 | // Querying an Array 63 | 64 | - (NSUInteger) count; 65 | - (NSUInteger) capacity; 66 | - (NSUInteger) indexOfObject:(id)object; 67 | - (id) objectAtIndex:(NSUInteger)index; 68 | - (BOOL) containsObject:(id)object; 69 | //- (id) randomObject; 70 | - (id) lastObject; 71 | - (NSArray*) getNSArray; 72 | 73 | 74 | // Adding Objects 75 | 76 | - (void) addObject:(id)object; 77 | - (void) addObjectsFromArray:(CCArray*)otherArray; 78 | - (void) addObjectsFromNSArray:(NSArray*)otherArray; 79 | - (void) insertObject:(id)object atIndex:(NSUInteger)index; 80 | 81 | 82 | // Removing Objects 83 | 84 | - (void) removeLastObject; 85 | - (void) removeObject:(id)object; 86 | - (void) removeObjectAtIndex:(NSUInteger)index; 87 | - (void) removeObjectsInArray:(CCArray*)otherArray; 88 | - (void) removeAllObjects; 89 | - (void) fastRemoveObject:(id)object; 90 | - (void) fastRemoveObjectAtIndex:(NSUInteger)index; 91 | 92 | 93 | // Rearranging Content 94 | 95 | - (void) exchangeObject:(id)object1 withObject:(id)object2; 96 | - (void) exchangeObjectAtIndex:(NSUInteger)index1 withObjectAtIndex:(NSUInteger)index2; 97 | - (void) reverseObjects; 98 | - (void) reduceMemoryFootprint; 99 | 100 | // Sending Messages to Elements 101 | 102 | - (void) makeObjectsPerformSelector:(SEL)aSelector; 103 | - (void) makeObjectsPerformSelector:(SEL)aSelector withObject:(id)object; 104 | 105 | 106 | @end 107 | -------------------------------------------------------------------------------- /Tests/ObjectsForTests/CCArray.m: -------------------------------------------------------------------------------- 1 | /* 2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org 3 | * 4 | * Copyright (c) 2010 ForzeField Studios S.L. http://forzefield.com 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | */ 24 | 25 | #import "CCArray.h" 26 | 27 | 28 | @implementation CCArray 29 | 30 | + (id) array 31 | { 32 | return [[[self alloc] init] autorelease]; 33 | } 34 | 35 | + (id) arrayWithCapacity:(NSUInteger)capacity 36 | { 37 | return [[[self alloc] initWithCapacity:capacity] autorelease]; 38 | } 39 | 40 | + (id) arrayWithCCArray:(CCArray*)otherArray 41 | { 42 | return [[(CCArray*)[self alloc] initWithCCArray:otherArray] autorelease]; 43 | } 44 | 45 | + (id) arrayWithArray:(NSArray*)otherArray 46 | { 47 | return [[(CCArray*)[self alloc] initWithArray:otherArray] autorelease]; 48 | } 49 | 50 | - (id) init 51 | { 52 | self = [self initWithCapacity:2]; 53 | return self; 54 | } 55 | 56 | - (id) initWithCapacity:(NSUInteger)capacity 57 | { 58 | self = [super init]; 59 | if (self != nil) { 60 | data = ccArrayNew(capacity); 61 | } 62 | return self; 63 | } 64 | 65 | - (id) initWithCCArray:(CCArray*)otherArray 66 | { 67 | self = [self initWithCapacity:otherArray->data->num]; 68 | if (self != nil) { 69 | [self addObjectsFromArray:otherArray]; 70 | } 71 | return self; 72 | } 73 | 74 | - (id) initWithArray:(NSArray*)otherArray 75 | { 76 | self = [self initWithCapacity:otherArray.count]; 77 | if (self != nil) { 78 | [self addObjectsFromNSArray:otherArray]; 79 | } 80 | return self; 81 | } 82 | 83 | - (id) initWithCoder:(NSCoder*)coder 84 | { 85 | self = [self initWithArray:[coder decodeObjectForKey:@"nsarray"]]; 86 | return self; 87 | } 88 | 89 | 90 | #pragma mark Querying an Array 91 | 92 | - (NSUInteger) count 93 | { 94 | return data->num; 95 | } 96 | 97 | - (NSUInteger) capacity 98 | { 99 | return data->max; 100 | } 101 | 102 | - (NSUInteger) indexOfObject:(id)object 103 | { 104 | return ccArrayGetIndexOfObject(data, object); 105 | } 106 | 107 | - (id) objectAtIndex:(NSUInteger)index 108 | { 109 | NSAssert2( index < data->num, @"index out of range in objectAtIndex(%d), index %i", data->num, index ); 110 | 111 | return data->arr[index]; 112 | } 113 | 114 | - (BOOL) containsObject:(id)object 115 | { 116 | return ccArrayContainsObject(data, object); 117 | } 118 | 119 | - (id) lastObject 120 | { 121 | if( data->num > 0 ) 122 | return data->arr[data->num-1]; 123 | return nil; 124 | } 125 | // 126 | //- (id) randomObject 127 | //{ 128 | // if(data->num==0) return nil; 129 | // return data->arr[(int)(data->num*CCRANDOM_0_1())]; 130 | //} 131 | 132 | - (NSArray*) getNSArray 133 | { 134 | return [NSArray arrayWithObjects:data->arr count:data->num]; 135 | } 136 | 137 | 138 | #pragma mark Adding Objects 139 | 140 | - (void) addObject:(id)object 141 | { 142 | ccArrayAppendObjectWithResize(data, object); 143 | } 144 | 145 | - (void) addObjectsFromArray:(CCArray*)otherArray 146 | { 147 | ccArrayAppendArrayWithResize(data, otherArray->data); 148 | } 149 | 150 | - (void) addObjectsFromNSArray:(NSArray*)otherArray 151 | { 152 | ccArrayEnsureExtraCapacity(data, otherArray.count); 153 | for(id object in otherArray) 154 | ccArrayAppendObject(data, object); 155 | } 156 | 157 | - (void) insertObject:(id)object atIndex:(NSUInteger)index 158 | { 159 | ccArrayInsertObjectAtIndex(data, object, index); 160 | } 161 | 162 | 163 | #pragma mark Removing Objects 164 | 165 | - (void) removeObject:(id)object 166 | { 167 | ccArrayRemoveObject(data, object); 168 | } 169 | 170 | - (void) removeObjectAtIndex:(NSUInteger)index 171 | { 172 | ccArrayRemoveObjectAtIndex(data, index); 173 | } 174 | 175 | - (void) fastRemoveObject:(id)object 176 | { 177 | ccArrayFastRemoveObject(data, object); 178 | } 179 | 180 | - (void) fastRemoveObjectAtIndex:(NSUInteger)index 181 | { 182 | ccArrayFastRemoveObjectAtIndex(data, index); 183 | } 184 | 185 | - (void) removeObjectsInArray:(CCArray*)otherArray 186 | { 187 | ccArrayRemoveArray(data, otherArray->data); 188 | } 189 | 190 | - (void) removeLastObject 191 | { 192 | NSAssert( data->num > 0, @"no objects added" ); 193 | 194 | ccArrayRemoveObjectAtIndex(data, data->num-1); 195 | } 196 | 197 | - (void) removeAllObjects 198 | { 199 | ccArrayRemoveAllObjects(data); 200 | } 201 | 202 | 203 | #pragma mark Rearranging Content 204 | 205 | - (void) exchangeObject:(id)object1 withObject:(id)object2 206 | { 207 | NSUInteger index1 = ccArrayGetIndexOfObject(data, object1); 208 | if(index1 == NSNotFound) return; 209 | NSUInteger index2 = ccArrayGetIndexOfObject(data, object2); 210 | if(index2 == NSNotFound) return; 211 | 212 | ccArraySwapObjectsAtIndexes(data, index1, index2); 213 | } 214 | 215 | - (void) exchangeObjectAtIndex:(NSUInteger)index1 withObjectAtIndex:(NSUInteger)index2 216 | { 217 | ccArraySwapObjectsAtIndexes(data, index1, index2); 218 | } 219 | 220 | - (void) reverseObjects 221 | { 222 | if (data->num > 1) 223 | { 224 | //floor it since in case of a oneven number the number of swaps stays the same 225 | int count = (int) floorf(data->num/2.f); 226 | NSUInteger maxIndex = data->num - 1; 227 | 228 | for (int i = 0; i < count ; i++) 229 | { 230 | ccArraySwapObjectsAtIndexes(data, i, maxIndex); 231 | maxIndex--; 232 | } 233 | } 234 | } 235 | 236 | - (void) reduceMemoryFootprint 237 | { 238 | ccArrayShrink(data); 239 | } 240 | 241 | #pragma mark Sending Messages to Elements 242 | 243 | - (void) makeObjectsPerformSelector:(SEL)aSelector 244 | { 245 | ccArrayMakeObjectsPerformSelector(data, aSelector); 246 | } 247 | 248 | - (void) makeObjectsPerformSelector:(SEL)aSelector withObject:(id)object 249 | { 250 | ccArrayMakeObjectsPerformSelectorWithObject(data, aSelector, object); 251 | } 252 | 253 | 254 | #pragma mark CCArray - NSFastEnumeration protocol 255 | 256 | - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len 257 | { 258 | if(state->state == 1) return 0; 259 | 260 | state->mutationsPtr = (unsigned long *)self; 261 | state->itemsPtr = &data->arr[0]; 262 | state->state = 1; 263 | return data->num; 264 | } 265 | 266 | 267 | #pragma mark CCArray - NSCopying protocol 268 | 269 | - (id)copyWithZone:(NSZone *)zone 270 | { 271 | NSArray *nsArray = [self getNSArray]; 272 | CCArray *newArray = [[[self class] allocWithZone:zone] initWithArray:nsArray]; 273 | return newArray; 274 | } 275 | 276 | - (void) encodeWithCoder:(NSCoder *)coder 277 | { 278 | [coder encodeObject:[self getNSArray] forKey:@"nsarray"]; 279 | } 280 | 281 | #pragma mark 282 | 283 | - (void) dealloc 284 | { 285 | ccArrayFree(data); 286 | [super dealloc]; 287 | } 288 | 289 | @end 290 | -------------------------------------------------------------------------------- /Tests/ObjectsForTests/Foo.h: -------------------------------------------------------------------------------- 1 | // 2 | // Foo.h 3 | // AutoMagicCoding 4 | // 5 | // 31.08.11. 6 | // Copyright 2011 Stepan Generalov. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import 27 | #import "Bar.h" 28 | #import "NSObject+AutoMagicCoding.h" 29 | 30 | @interface Foo : NSObject 31 | { 32 | int _integerValue; 33 | Bar *_publicBar; 34 | 35 | Bar *_privateBar; 36 | } 37 | 38 | @property int integerValue; 39 | @property(retain) Bar *publicBar; 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /Tests/ObjectsForTests/Foo.m: -------------------------------------------------------------------------------- 1 | // 2 | // Foo.m 3 | // AutoMagicCoding 4 | // 5 | // 31.08.11. 6 | // Copyright 2011 Stepan Generalov. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import "Foo.h" 27 | #import "NSObject+AutoMagicCoding.h" 28 | 29 | @implementation Foo 30 | 31 | @synthesize integerValue = _integerValue; 32 | @synthesize publicBar = _publicBar; 33 | 34 | + (BOOL) AMCEnabled 35 | { 36 | return YES; 37 | } 38 | 39 | - (id)initWithDictionaryRepresentation: (NSDictionary *) aDict 40 | { 41 | self = [super initWithDictionaryRepresentation: aDict]; 42 | if (self) { 43 | [_publicBar retain]; 44 | } 45 | 46 | return self; 47 | } 48 | 49 | - (AMCFieldType) AMCFieldTypeForValueWithKey: (NSString *) aKey 50 | { 51 | if ([aKey isEqualToString:@"privateBar"]) 52 | { 53 | return kAMCFieldTypeCustomObject; 54 | } 55 | 56 | return [super AMCFieldTypeForValueWithKey: aKey]; 57 | } 58 | 59 | - (NSArray *) AMCKeysForDictionaryRepresentation 60 | { 61 | NSArray *array = [super AMCKeysForDictionaryRepresentation]; 62 | return [array arrayByAddingObject:@"privateBar"]; 63 | } 64 | 65 | - (void) dealloc 66 | { 67 | [_publicBar release]; 68 | _publicBar = nil; 69 | 70 | [super dealloc]; 71 | } 72 | 73 | - (BOOL) isEqual:(id)object 74 | { 75 | if ([object isMemberOfClass:[self class]]) 76 | { 77 | Foo *other = (Foo *)object; 78 | if(self.integerValue == other.integerValue) 79 | { 80 | BOOL equal = YES; 81 | 82 | if (self.publicBar != other.publicBar) 83 | { 84 | if (![self.publicBar isEqual: other.publicBar]) 85 | equal = NO; 86 | } 87 | 88 | if ( _privateBar != [other valueForKey: @"privateBar" ]) 89 | { 90 | if (![_privateBar isEqual: [other valueForKey: @"privateBar" ]]) 91 | equal = NO; 92 | } 93 | 94 | 95 | return equal; 96 | } 97 | 98 | return NO; 99 | } 100 | 101 | return [super isEqual: object]; 102 | } 103 | 104 | - (NSString *) description 105 | { 106 | return [NSString stringWithFormat:@"%@ integerValue={%d}, publicBar = %@, pribateBar = %@", 107 | [self class], 108 | self.integerValue, 109 | self.publicBar, 110 | _privateBar ]; 111 | } 112 | 113 | @end 114 | -------------------------------------------------------------------------------- /Tests/ObjectsForTests/FooWithCollections.h: -------------------------------------------------------------------------------- 1 | // 2 | // FooWithCollections.h 3 | // AutoMagicCoding 4 | // 5 | // 02.09.11. 6 | // Copyright 2011 Stepan Generalov. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import 27 | 28 | @interface FooWithCollections : NSObject 29 | { 30 | NSArray *_array; 31 | NSDictionary *_dict; 32 | } 33 | 34 | @property(readwrite, retain) NSArray *array; 35 | @property(readwrite, retain) NSDictionary *dict; 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /Tests/ObjectsForTests/FooWithCollections.m: -------------------------------------------------------------------------------- 1 | // 2 | // FooWithCollections.m 3 | // AutoMagicCoding 4 | // 5 | // 02.09.11. 6 | // Copyright 2011 Stepan Generalov. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import "FooWithCollections.h" 27 | 28 | @implementation FooWithCollections 29 | @synthesize array = _array; 30 | @synthesize dict = _dict; 31 | 32 | + (BOOL) AMCEnabled 33 | { 34 | return YES; 35 | } 36 | 37 | - (void) dealloc 38 | { 39 | self.array = nil; 40 | self.dict = nil; 41 | 42 | [super dealloc]; 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /Tests/ObjectsForTests/FooWithCustomCollection.h: -------------------------------------------------------------------------------- 1 | // 2 | // FooWithCustomCollection.h 3 | // AutoMagicCoding-iOS 4 | // 5 | // 04.09.11. 6 | // Copyright 2011 Stepan Generalov. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import 27 | #import "CCArray.h" 28 | 29 | @interface FooWithCustomCollection : NSObject 30 | { 31 | CCArray *_array; 32 | } 33 | @property(readwrite, retain) CCArray *array; 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /Tests/ObjectsForTests/FooWithCustomCollection.m: -------------------------------------------------------------------------------- 1 | // 2 | // FooWithCustomCollection.m 3 | // AutoMagicCoding-iOS 4 | // 5 | // 04.09.11. 6 | // Copyright 2011 Stepan Generalov. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import "FooWithCustomCollection.h" 27 | 28 | @implementation FooWithCustomCollection 29 | 30 | @synthesize array = _array; 31 | 32 | + (BOOL) AMCEnabled 33 | { 34 | return YES; 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /Tests/ObjectsForTests/FooWithMutableCollections.h: -------------------------------------------------------------------------------- 1 | // 2 | // FooWithMutableCollections.h 3 | // AutoMagicCoding 4 | // 5 | // 02.09.11. 6 | // Copyright 2011 Stepan Generalov. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import 27 | 28 | /** @class FooWithMutableCollections Almost like FooWithCollections, but ivars & properties are mutable. 29 | * You must use NSMutableArray instead of NSArray in order to AMC work properly. 30 | * NSObject(AutoMagicCoding)#fieldTypeForValueWithKey: uses property type to get class 31 | * and ask it about is it mutable or not. 32 | */ 33 | @interface FooWithMutableCollections : NSObject 34 | { 35 | NSMutableArray *_array; 36 | NSMutableDictionary *_dict; 37 | } 38 | 39 | @property(readwrite, retain) NSMutableArray *array; 40 | @property(readwrite, retain) NSMutableDictionary *dict; 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /Tests/ObjectsForTests/FooWithMutableCollections.m: -------------------------------------------------------------------------------- 1 | // 2 | // FooWithMutableCollections.m 3 | // AutoMagicCoding 4 | // 5 | // 02.09.11. 6 | // Copyright 2011 Stepan Generalov. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import "FooWithMutableCollections.h" 27 | 28 | @implementation FooWithMutableCollections 29 | 30 | @synthesize array = _array; 31 | @synthesize dict = _dict; 32 | 33 | + (BOOL) AMCEnabled 34 | { 35 | return YES; 36 | } 37 | 38 | - (void) dealloc 39 | { 40 | self.array = nil; 41 | self.dict = nil; 42 | 43 | [super dealloc]; 44 | } 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /Tests/ObjectsForTests/FooWithSctructs.h: -------------------------------------------------------------------------------- 1 | // 2 | // FooWithSctructs.h 3 | // AutoMagicCoding-iOS 4 | // 5 | // 04.09.11. 6 | // Copyright 2011 Stepan Generalov. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import 27 | 28 | struct CustomStruct { 29 | NSUInteger ui; 30 | float f; 31 | double d; 32 | NSInteger i; 33 | }; 34 | typedef struct CustomStruct CustomStruct; 35 | 36 | NSString *NSStringFromCustomStruct(CustomStruct custom); 37 | CustomStruct CustomStructFromNSString(NSString *string); 38 | 39 | @interface FooWithSctructs : NSObject 40 | { 41 | CGPoint _point; 42 | CGSize _size; 43 | CGRect _rect; 44 | 45 | CustomStruct _customStruct; 46 | } 47 | 48 | @property CGPoint point; 49 | @property CGSize size; 50 | @property CGRect rect; 51 | @property CustomStruct customStruct; 52 | 53 | @end 54 | -------------------------------------------------------------------------------- /Tests/ObjectsForTests/FooWithSctructs.m: -------------------------------------------------------------------------------- 1 | // 2 | // FooWithSctructs.m 3 | // AutoMagicCoding-iOS 4 | // 5 | // 04.09.11. 6 | // Copyright 2011 Stepan Generalov. 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | #import "FooWithSctructs.h" 27 | #import "NSObject+AutoMagicCoding.h" 28 | 29 | NSString *NSStringFromCustomStruct(CustomStruct custom) 30 | { 31 | return [NSString stringWithFormat:@"ui=%d, f=%f, d=%f, i=%d", custom.ui, custom.f, custom.d, custom.i]; 32 | } 33 | 34 | CustomStruct CustomStructFromNSString(NSString *string) 35 | { 36 | CustomStruct result; 37 | 38 | NSArray *components = [string componentsSeparatedByString:@", "]; 39 | for (NSString *component in components) 40 | { 41 | NSArray *keyValue = [component componentsSeparatedByString:@"="]; 42 | if ([keyValue count] > 1) 43 | { 44 | NSString *key = [keyValue objectAtIndex: 0]; 45 | NSString *value = [keyValue objectAtIndex:1]; 46 | 47 | if ([key isEqualToString:@"ui"]) 48 | { 49 | result.ui = [value integerValue]; 50 | } 51 | else if ([key isEqualToString:@"f"]) 52 | { 53 | result.f = [value floatValue]; 54 | } 55 | else if ([key isEqualToString:@"d"]) 56 | { 57 | result.d = [value doubleValue]; 58 | } 59 | else if ([key isEqualToString:@"i"]) 60 | { 61 | result.i = [value integerValue]; 62 | } 63 | } 64 | } 65 | 66 | return result; 67 | } 68 | 69 | @implementation FooWithSctructs 70 | 71 | @synthesize rect = _rect, point = _point, size = _size; 72 | @synthesize customStruct = _customStruct; 73 | 74 | + (BOOL) AMCEnabled 75 | { 76 | return YES; 77 | } 78 | 79 | - (id)init 80 | { 81 | self = [super init]; 82 | if (self) { 83 | // Initialization code here. 84 | } 85 | 86 | return self; 87 | } 88 | 89 | #pragma mark Custom Struct Support 90 | 91 | - (NSString *) AMCEncodeStructWithValue: (NSValue *) structValue withName: (NSString *) structName 92 | { 93 | if ([structName isEqualToString: @"CustomStruct" ]) 94 | { 95 | CustomStruct custom; 96 | [structValue getValue: &custom]; 97 | 98 | return NSStringFromCustomStruct(custom); 99 | } 100 | 101 | return [super AMCEncodeStructWithValue: structValue withName: structName]; 102 | } 103 | 104 | - (NSValue *) AMCDecodeStructFromString: (NSString *)value withName: (NSString *) structName 105 | { 106 | if ([structName isEqualToString: @"CustomStruct" ]) 107 | { 108 | CustomStruct custom = CustomStructFromNSString(value); 109 | return [NSValue valueWithBytes: &custom objCType:@encode(CustomStruct)]; 110 | } 111 | 112 | return [super AMCDecodeStructFromString: value withName: structName]; 113 | } 114 | 115 | @end 116 | -------------------------------------------------------------------------------- /Tests/ObjectsForTests/ccCArray.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2007 Scott Lembcke 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in 11 | * all copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | * SOFTWARE. 20 | */ 21 | 22 | /** 23 | @file 24 | Based on Chipmunk cpArray. 25 | ccArray is a faster alternative to NSMutableArray, it does pretty much the 26 | same thing (stores NSObjects and retains/releases them appropriately). It's 27 | faster because: 28 | - it uses a plain C interface so it doesn't incur Objective-c messaging overhead 29 | - it assumes you know what you're doing, so it doesn't spend time on safety checks 30 | (index out of bounds, required capacity etc.) 31 | - comparisons are done using pointer equality instead of isEqual 32 | 33 | There are 2 kind of functions: 34 | - ccArray functions that manipulates objective-c objects (retain and release are performanced) 35 | - ccCArray functions that manipulates values like if they were standard C structures (no retain/release is performed) 36 | */ 37 | 38 | #ifndef CC_ARRAY_H 39 | #define CC_ARRAY_H 40 | 41 | #import 42 | 43 | #import 44 | #import 45 | 46 | 47 | #pragma mark - 48 | #pragma mark ccArray for Objects 49 | 50 | // Easy integration 51 | #define CCARRAYDATA_FOREACH(__array__, __object__) \ 52 | __object__=__array__->arr[0]; for(NSUInteger i=0, num=__array__->num; iarr[i]) \ 53 | 54 | 55 | typedef struct ccArray { 56 | NSUInteger num, max; 57 | id *arr; 58 | } ccArray; 59 | 60 | /** Allocates and initializes a new array with specified capacity */ 61 | static inline ccArray* ccArrayNew(NSUInteger capacity) { 62 | if (capacity == 0) 63 | capacity = 1; 64 | 65 | ccArray *arr = (ccArray*)malloc( sizeof(ccArray) ); 66 | arr->num = 0; 67 | arr->arr = (id*) malloc( capacity * sizeof(id) ); 68 | arr->max = capacity; 69 | 70 | return arr; 71 | } 72 | 73 | static inline void ccArrayRemoveAllObjects(ccArray *arr); 74 | 75 | /** Frees array after removing all remaining objects. Silently ignores nil arr. */ 76 | static inline void ccArrayFree(ccArray *arr) 77 | { 78 | if( arr == nil ) return; 79 | 80 | ccArrayRemoveAllObjects(arr); 81 | 82 | free(arr->arr); 83 | free(arr); 84 | } 85 | 86 | /** Doubles array capacity */ 87 | static inline void ccArrayDoubleCapacity(ccArray *arr) 88 | { 89 | arr->max *= 2; 90 | id *newArr = (id *)realloc( arr->arr, arr->max * sizeof(id) ); 91 | // will fail when there's not enough memory 92 | NSCAssert(newArr != NULL, @"ccArrayDoubleCapacity failed. Not enough memory"); 93 | arr->arr = newArr; 94 | } 95 | 96 | /** Increases array capacity such that max >= num + extra. */ 97 | static inline void ccArrayEnsureExtraCapacity(ccArray *arr, NSUInteger extra) 98 | { 99 | while (arr->max < arr->num + extra) 100 | ccArrayDoubleCapacity(arr); 101 | } 102 | 103 | /** shrinks the array so the memory footprint corresponds with the number of items */ 104 | static inline void ccArrayShrink(ccArray *arr) 105 | { 106 | NSUInteger newSize; 107 | 108 | //only resize when necessary 109 | if (arr->max > arr->num && !(arr->num==0 && arr->max==1)) 110 | { 111 | if (arr->num!=0) 112 | { 113 | newSize=arr->num; 114 | arr->max=arr->num; 115 | } 116 | else 117 | {//minimum capacity of 1, with 0 elements the array would be free'd by realloc 118 | newSize=1; 119 | arr->max=1; 120 | } 121 | 122 | arr->arr = (id*) realloc(arr->arr,newSize * sizeof(id) ); 123 | NSCAssert(arr->arr!=NULL,@"could not reallocate the memory"); 124 | } 125 | } 126 | 127 | /** Returns index of first occurence of object, NSNotFound if object not found. */ 128 | static inline NSUInteger ccArrayGetIndexOfObject(ccArray *arr, id object) 129 | { 130 | for( NSUInteger i = 0; i < arr->num; i++) 131 | if( arr->arr[i] == object ) return i; 132 | 133 | return NSNotFound; 134 | } 135 | 136 | /** Returns a Boolean value that indicates whether object is present in array. */ 137 | static inline BOOL ccArrayContainsObject(ccArray *arr, id object) 138 | { 139 | return ccArrayGetIndexOfObject(arr, object) != NSNotFound; 140 | } 141 | 142 | /** Appends an object. Bahaviour undefined if array doesn't have enough capacity. */ 143 | static inline void ccArrayAppendObject(ccArray *arr, id object) 144 | { 145 | arr->arr[arr->num] = [object retain]; 146 | arr->num++; 147 | } 148 | 149 | /** Appends an object. Capacity of arr is increased if needed. */ 150 | static inline void ccArrayAppendObjectWithResize(ccArray *arr, id object) 151 | { 152 | ccArrayEnsureExtraCapacity(arr, 1); 153 | ccArrayAppendObject(arr, object); 154 | } 155 | 156 | /** Appends objects from plusArr to arr. Behaviour undefined if arr doesn't have 157 | enough capacity. */ 158 | static inline void ccArrayAppendArray(ccArray *arr, ccArray *plusArr) 159 | { 160 | for( NSUInteger i = 0; i < plusArr->num; i++) 161 | ccArrayAppendObject(arr, plusArr->arr[i]); 162 | } 163 | 164 | /** Appends objects from plusArr to arr. Capacity of arr is increased if needed. */ 165 | static inline void ccArrayAppendArrayWithResize(ccArray *arr, ccArray *plusArr) 166 | { 167 | ccArrayEnsureExtraCapacity(arr, plusArr->num); 168 | ccArrayAppendArray(arr, plusArr); 169 | } 170 | 171 | /** Inserts an object at index */ 172 | static inline void ccArrayInsertObjectAtIndex(ccArray *arr, id object, NSUInteger index) 173 | { 174 | NSCAssert(index<=arr->num, @"Invalid index. Out of bounds"); 175 | 176 | ccArrayEnsureExtraCapacity(arr, 1); 177 | 178 | NSUInteger remaining = arr->num - index; 179 | if( remaining > 0) 180 | memmove(&arr->arr[index+1], &arr->arr[index], sizeof(id) * remaining ); 181 | 182 | arr->arr[index] = [object retain]; 183 | arr->num++; 184 | } 185 | 186 | /** Swaps two objects */ 187 | static inline void ccArraySwapObjectsAtIndexes(ccArray *arr, NSUInteger index1, NSUInteger index2) 188 | { 189 | NSCAssert(index1 < arr->num, @"(1) Invalid index. Out of bounds"); 190 | NSCAssert(index2 < arr->num, @"(2) Invalid index. Out of bounds"); 191 | 192 | id object1 = arr->arr[index1]; 193 | 194 | arr->arr[index1] = arr->arr[index2]; 195 | arr->arr[index2] = object1; 196 | } 197 | 198 | /** Removes all objects from arr */ 199 | static inline void ccArrayRemoveAllObjects(ccArray *arr) 200 | { 201 | while( arr->num > 0 ) 202 | [arr->arr[--arr->num] release]; 203 | } 204 | 205 | /** Removes object at specified index and pushes back all subsequent objects. 206 | Behaviour undefined if index outside [0, num-1]. */ 207 | static inline void ccArrayRemoveObjectAtIndex(ccArray *arr, NSUInteger index) 208 | { 209 | [arr->arr[index] release]; 210 | arr->num--; 211 | 212 | NSUInteger remaining = arr->num - index; 213 | if(remaining>0) 214 | memmove(&arr->arr[index], &arr->arr[index+1], remaining * sizeof(id)); 215 | } 216 | 217 | /** Removes object at specified index and fills the gap with the last object, 218 | thereby avoiding the need to push back subsequent objects. 219 | Behaviour undefined if index outside [0, num-1]. */ 220 | static inline void ccArrayFastRemoveObjectAtIndex(ccArray *arr, NSUInteger index) 221 | { 222 | [arr->arr[index] release]; 223 | NSUInteger last = --arr->num; 224 | arr->arr[index] = arr->arr[last]; 225 | } 226 | 227 | static inline void ccArrayFastRemoveObject(ccArray *arr, id object) 228 | { 229 | NSUInteger index = ccArrayGetIndexOfObject(arr, object); 230 | if (index != NSNotFound) 231 | ccArrayFastRemoveObjectAtIndex(arr, index); 232 | } 233 | 234 | /** Searches for the first occurance of object and removes it. If object is not 235 | found the function has no effect. */ 236 | static inline void ccArrayRemoveObject(ccArray *arr, id object) 237 | { 238 | NSUInteger index = ccArrayGetIndexOfObject(arr, object); 239 | if (index != NSNotFound) 240 | ccArrayRemoveObjectAtIndex(arr, index); 241 | } 242 | 243 | /** Removes from arr all objects in minusArr. For each object in minusArr, the 244 | first matching instance in arr will be removed. */ 245 | static inline void ccArrayRemoveArray(ccArray *arr, ccArray *minusArr) 246 | { 247 | for( NSUInteger i = 0; i < minusArr->num; i++) 248 | ccArrayRemoveObject(arr, minusArr->arr[i]); 249 | } 250 | 251 | /** Removes from arr all objects in minusArr. For each object in minusArr, all 252 | matching instances in arr will be removed. */ 253 | static inline void ccArrayFullRemoveArray(ccArray *arr, ccArray *minusArr) 254 | { 255 | NSUInteger back = 0; 256 | 257 | for( NSUInteger i = 0; i < arr->num; i++) { 258 | if( ccArrayContainsObject(minusArr, arr->arr[i]) ) { 259 | [arr->arr[i] release]; 260 | back++; 261 | } else 262 | arr->arr[i - back] = arr->arr[i]; 263 | } 264 | 265 | arr->num -= back; 266 | } 267 | 268 | /** Sends to each object in arr the message identified by given selector. */ 269 | static inline void ccArrayMakeObjectsPerformSelector(ccArray *arr, SEL sel) 270 | { 271 | for( NSUInteger i = 0; i < arr->num; i++) 272 | [arr->arr[i] performSelector:sel]; 273 | } 274 | 275 | static inline void ccArrayMakeObjectsPerformSelectorWithObject(ccArray *arr, SEL sel, id object) 276 | { 277 | for( NSUInteger i = 0; i < arr->num; i++) 278 | [arr->arr[i] performSelector:sel withObject:object]; 279 | } 280 | 281 | 282 | #pragma mark - 283 | #pragma mark ccCArray for Values (c structures) 284 | 285 | typedef ccArray ccCArray; 286 | 287 | static inline void ccCArrayRemoveAllValues(ccCArray *arr); 288 | 289 | /** Allocates and initializes a new C array with specified capacity */ 290 | static inline ccCArray* ccCArrayNew(NSUInteger capacity) { 291 | if (capacity == 0) 292 | capacity = 1; 293 | 294 | ccCArray *arr = (ccCArray*)malloc( sizeof(ccCArray) ); 295 | arr->num = 0; 296 | arr->arr = (id*) malloc( capacity * sizeof(id) ); 297 | arr->max = capacity; 298 | 299 | return arr; 300 | } 301 | 302 | /** Frees C array after removing all remaining values. Silently ignores nil arr. */ 303 | static inline void ccCArrayFree(ccCArray *arr) 304 | { 305 | if( arr == nil ) return; 306 | 307 | ccCArrayRemoveAllValues(arr); 308 | 309 | free(arr->arr); 310 | free(arr); 311 | } 312 | 313 | /** Doubles C array capacity */ 314 | static inline void ccCArrayDoubleCapacity(ccCArray *arr) 315 | { 316 | ccArrayDoubleCapacity(arr); 317 | } 318 | 319 | /** Increases array capacity such that max >= num + extra. */ 320 | static inline void ccCArrayEnsureExtraCapacity(ccCArray *arr, NSUInteger extra) 321 | { 322 | ccArrayEnsureExtraCapacity(arr,extra); 323 | } 324 | 325 | /** Returns index of first occurence of value, NSNotFound if value not found. */ 326 | static inline NSUInteger ccCArrayGetIndexOfValue(ccCArray *arr, void* value) 327 | { 328 | for( NSUInteger i = 0; i < arr->num; i++) 329 | if( arr->arr[i] == value ) return i; 330 | return NSNotFound; 331 | } 332 | 333 | /** Returns a Boolean value that indicates whether value is present in the C array. */ 334 | static inline BOOL ccCArrayContainsValue(ccCArray *arr, void* value) 335 | { 336 | return ccCArrayGetIndexOfValue(arr, value) != NSNotFound; 337 | } 338 | 339 | /** Inserts a value at a certain position. Behaviour undefined if aray doesn't have enough capacity */ 340 | static inline void ccCArrayInsertValueAtIndex( ccCArray *arr, void *value, NSUInteger index) 341 | { 342 | NSCAssert( index < arr->max, @"ccCArrayInsertValueAtIndex: invalid index"); 343 | 344 | NSUInteger remaining = arr->num - index; 345 | 346 | // last Value doesn't need to be moved 347 | if( remaining > 0) { 348 | // tex coordinates 349 | memmove( &arr->arr[index+1],&arr->arr[index], sizeof(void*) * remaining ); 350 | } 351 | 352 | arr->num++; 353 | arr->arr[index] = (id) value; 354 | } 355 | 356 | /** Appends an value. Bahaviour undefined if array doesn't have enough capacity. */ 357 | static inline void ccCArrayAppendValue(ccCArray *arr, void* value) 358 | { 359 | arr->arr[arr->num] = (id) value; 360 | arr->num++; 361 | } 362 | 363 | /** Appends an value. Capacity of arr is increased if needed. */ 364 | static inline void ccCArrayAppendValueWithResize(ccCArray *arr, void* value) 365 | { 366 | ccCArrayEnsureExtraCapacity(arr, 1); 367 | ccCArrayAppendValue(arr, value); 368 | } 369 | 370 | /** Appends values from plusArr to arr. Behaviour undefined if arr doesn't have 371 | enough capacity. */ 372 | static inline void ccCArrayAppendArray(ccCArray *arr, ccCArray *plusArr) 373 | { 374 | for( NSUInteger i = 0; i < plusArr->num; i++) 375 | ccCArrayAppendValue(arr, plusArr->arr[i]); 376 | } 377 | 378 | /** Appends values from plusArr to arr. Capacity of arr is increased if needed. */ 379 | static inline void ccCArrayAppendArrayWithResize(ccCArray *arr, ccCArray *plusArr) 380 | { 381 | ccCArrayEnsureExtraCapacity(arr, plusArr->num); 382 | ccCArrayAppendArray(arr, plusArr); 383 | } 384 | 385 | /** Removes all values from arr */ 386 | static inline void ccCArrayRemoveAllValues(ccCArray *arr) 387 | { 388 | arr->num = 0; 389 | } 390 | 391 | /** Removes value at specified index and pushes back all subsequent values. 392 | Behaviour undefined if index outside [0, num-1]. 393 | @since v0.99.4 394 | */ 395 | static inline void ccCArrayRemoveValueAtIndex(ccCArray *arr, NSUInteger index) 396 | { 397 | for( NSUInteger last = --arr->num; index < last; index++) 398 | arr->arr[index] = arr->arr[index + 1]; 399 | } 400 | 401 | /** Removes value at specified index and fills the gap with the last value, 402 | thereby avoiding the need to push back subsequent values. 403 | Behaviour undefined if index outside [0, num-1]. 404 | @since v0.99.4 405 | */ 406 | static inline void ccCArrayFastRemoveValueAtIndex(ccCArray *arr, NSUInteger index) 407 | { 408 | NSUInteger last = --arr->num; 409 | arr->arr[index] = arr->arr[last]; 410 | } 411 | 412 | /** Searches for the first occurance of value and removes it. If value is not found the function has no effect. 413 | @since v0.99.4 414 | */ 415 | static inline void ccCArrayRemoveValue(ccCArray *arr, void* value) 416 | { 417 | NSUInteger index = ccCArrayGetIndexOfValue(arr, value); 418 | if (index != NSNotFound) 419 | ccCArrayRemoveValueAtIndex(arr, index); 420 | } 421 | 422 | /** Removes from arr all values in minusArr. For each Value in minusArr, the first matching instance in arr will be removed. 423 | @since v0.99.4 424 | */ 425 | static inline void ccCArrayRemoveArray(ccCArray *arr, ccCArray *minusArr) 426 | { 427 | for( NSUInteger i = 0; i < minusArr->num; i++) 428 | ccCArrayRemoveValue(arr, minusArr->arr[i]); 429 | } 430 | 431 | /** Removes from arr all values in minusArr. For each value in minusArr, all matching instances in arr will be removed. 432 | @since v0.99.4 433 | */ 434 | static inline void ccCArrayFullRemoveArray(ccCArray *arr, ccCArray *minusArr) 435 | { 436 | NSUInteger back = 0; 437 | 438 | for( NSUInteger i = 0; i < arr->num; i++) { 439 | if( ccCArrayContainsValue(minusArr, arr->arr[i]) ) { 440 | back++; 441 | } else 442 | arr->arr[i - back] = arr->arr[i]; 443 | } 444 | 445 | arr->num -= back; 446 | } 447 | #endif // CC_ARRAY_H 448 | --------------------------------------------------------------------------------