├── .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 |
13 |
17 |
21 |
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 |
--------------------------------------------------------------------------------