├── .travis.yml ├── Examples ├── AutoTodoList │ ├── AutoCoding │ │ ├── AutoCoding.h │ │ └── AutoCoding.m │ ├── Classes │ │ ├── NewItemViewController.h │ │ ├── NewItemViewController.m │ │ ├── NewItemViewController.xib │ │ ├── TodoItem.h │ │ ├── TodoItem.m │ │ ├── TodoList.h │ │ ├── TodoList.m │ │ ├── TodoListAppDelegate.h │ │ ├── TodoListAppDelegate.m │ │ ├── TodoListViewController.h │ │ ├── TodoListViewController.m │ │ └── TodoListViewController.xib │ ├── Default-568h@2x.png │ ├── HRAutoTodoList-Info.plist │ ├── HRAutoTodoList.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ └── WorkspaceSettings.xcsettings │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── HRAutoTodoList.xcscheme │ ├── HRAutoTodoList_Prefix.pch │ ├── MainWindow.xib │ ├── TodoList.plist │ └── main.m └── TodoList │ ├── Classes │ ├── NewItemViewController.h │ ├── NewItemViewController.m │ ├── NewItemViewController.xib │ ├── TodoItem.h │ ├── TodoItem.m │ ├── TodoList.h │ ├── TodoList.m │ ├── TodoListAppDelegate.h │ ├── TodoListAppDelegate.m │ ├── TodoListViewController.h │ ├── TodoListViewController.m │ └── TodoListViewController.xib │ ├── Default-568h@2x.png │ ├── HRTodoList-Info.plist │ ├── HRTodoList.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ └── HRTodoList.xcscheme │ ├── HRTodoList_Prefix.pch │ ├── MainWindow.xib │ ├── TodoList.plist │ └── main.m ├── HRCoder.podspec.json ├── HRCoder ├── HRCoder.h └── HRCoder.m ├── LICENCE.md ├── README.md └── Tests ├── UnitTests.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── WorkspaceSettings.xcsettings └── xcshareddata │ └── xcschemes │ └── UnitTests.xcscheme └── UnitTests ├── HRCoderTests.m └── UnitTests-Info.plist /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | osx_image: xcode9 3 | 4 | script: xcodebuild test -project Tests/UnitTests.xcodeproj -scheme UnitTests -destination 'platform=iOS Simulator,name=iPhone 8 Plus,OS=11.0' 5 | -------------------------------------------------------------------------------- /Examples/AutoTodoList/AutoCoding/AutoCoding.h: -------------------------------------------------------------------------------- 1 | // 2 | // AutoCoding.h 3 | // 4 | // Version 2.2.3 5 | // 6 | // Created by Nick Lockwood on 19/11/2011. 7 | // Copyright (c) 2011 Charcoal Design 8 | // 9 | // Distributed under the permissive zlib License 10 | // Get the latest version from here: 11 | // 12 | // https://github.com/nicklockwood/AutoCoding 13 | // 14 | // This software is provided 'as-is', without any express or implied warranty. 15 | // In no event will the authors be held liable for any damages arising from the 16 | // use of this software. 17 | // 18 | // Permission is granted to anyone to use this software for any purpose, 19 | // including commercial applications, and to alter it and redistribute it 20 | // freely, subject to the following restrictions: 21 | // 22 | // 1. The origin of this software must not be misrepresented; you must not 23 | // claim that you wrote the original software. If you use this software in a 24 | // product, an acknowledgment in the product documentation would be appreciated 25 | // but is not required. 26 | // 27 | // 2. Altered source versions must be plainly marked as such, and must not be 28 | // misrepresented as being the original software. 29 | // 30 | // 3. This notice may not be removed or altered from any source distribution. 31 | // 32 | 33 | #import 34 | 35 | NS_ASSUME_NONNULL_BEGIN 36 | 37 | @interface NSObject (AutoCoding) 38 | 39 | /** 40 | * Returns a dictionary containing the names and classes of all the properties of 41 | * the class that will be automatically saved, loaded and copied when the object 42 | * is archived using `NSKeyedArchiver/Unarchiver`. The values of the dictionary 43 | * represent the class used to encode each property (e.g. `NSString` for strings, 44 | * `NSNumber` for numeric values or booleans, `NSValue` for structs, etc). 45 | * 46 | * This dictionary is automatically generated by scanning the properties defined 47 | * in the class definition at runtime. Read-only and private properties will also 48 | * be coded as long as they have KVC-compliant ivar names (i.e. the ivar matches 49 | * the property name, or is the same but with a _ prefix). Any properties that 50 | * are not backed by an ivar, or whose ivar name does not match the property name 51 | * will not be encoded (this is a design feature, not a limitation - it makes it 52 | * easier to exclude properties from encoding) 53 | * 54 | * It is not normally necessary to override this method unless you wish to add 55 | * ivars for coding that do not have matching property definitions, or if you 56 | * wish to code virtual properties (properties or setter/getter method pairs that 57 | * are not backed by an ivar). If you wish to exclude certain properties from the 58 | * serialisation process, you can deliberately give them an non KVC-compliant 59 | * ivar name (see above). 60 | * 61 | * Note that this method only returns the properties defined on a particular 62 | * class and not any properties that are inherited from its superclasses. You 63 | * *do not* need to call `[super codableProperties]` if you override this method. 64 | */ 65 | + (NSDictionary *)codableProperties; 66 | 67 | /** 68 | * Populates the object's properties using the provided `NSCoder` object, based 69 | * on the `codableProperties` dictionary. This is called internally by the 70 | * `initWithCoder:` method, but may be useful if you wish to initialise an object 71 | * from a coded archive after it has already been created. You could even 72 | * initialise the object by merging the results of several different archives by 73 | * calling `setWithCoder:` more than once. 74 | */ 75 | - (void)setWithCoder:(NSCoder *)aDecoder; 76 | 77 | /** 78 | * Returns all the codable properties of the object, including those that are 79 | * inherited from superclasses. You should not override this method - if you 80 | * want to add additional properties, override the `+codableProperties` class 81 | * method instead. 82 | */ 83 | @property (nonatomic, readonly) NSDictionary *codableProperties; 84 | 85 | /** 86 | * Returns a dictionary of the values of all the codable properties of the 87 | * object. It is equivalent to calling `dictionaryWithValuesForKeys:` with the 88 | * result of `object.codableProperties.allKeys` as the parameter. 89 | */ 90 | @property (nonatomic, readonly) NSDictionary *dictionaryRepresentation; 91 | 92 | /** 93 | * Attempts to load the file using the following sequence: 1) If the file is an 94 | * NSCoded archive, load the root object and return it; 2) If the file is an 95 | * ordinary Plist, load and return the root object; 3) Return the raw data as an 96 | * `NSData` object. If the de-serialised object is not a subclass of the class 97 | * being used to load it, an exception will be thrown (to avoid this, call the 98 | * method on `NSObject` instead of a specific subclass). 99 | */ 100 | + (nullable instancetype)objectWithContentsOfFile:(NSString *)path; 101 | 102 | /** 103 | * Attempts to write the file to disk. This method is overridden by the 104 | * equivalent methods for `NSData`, `NSDictionary` and `NSArray`, which save the 105 | * file as a human-readable XML Plist rather than a binary NSCoded Plist archive, 106 | * but the `objectWithContentsOfFile:` method will correctly de-serialise these 107 | * again anyway. For any other object it will serialise the object using the 108 | * `NSCoding` protocol and write out the file as a NSCoded binary Plist archive. 109 | * Returns `YES` on success and `NO` on failure. 110 | */ 111 | - (BOOL)writeToFile:(NSString *)filePath atomically:(BOOL)useAuxiliaryFile; 112 | 113 | @end 114 | 115 | NS_ASSUME_NONNULL_END 116 | -------------------------------------------------------------------------------- /Examples/AutoTodoList/AutoCoding/AutoCoding.m: -------------------------------------------------------------------------------- 1 | // 2 | // AutoCoding.m 3 | // 4 | // Version 2.2.3 5 | // 6 | // Created by Nick Lockwood on 19/11/2011. 7 | // Copyright (c) 2011 Charcoal Design 8 | // 9 | // Distributed under the permissive zlib License 10 | // Get the latest version from here: 11 | // 12 | // https://github.com/nicklockwood/AutoCoding 13 | // 14 | // This software is provided 'as-is', without any express or implied 15 | // warranty. In no event will the authors be held liable for any damages 16 | // arising from the use of this software. 17 | // 18 | // Permission is granted to anyone to use this software for any purpose, 19 | // including commercial applications, and to alter it and redistribute it 20 | // freely, following restrictions: 21 | // 22 | // 1. The origin of this software must not be misrepresented; you must not 23 | // claim that you wrote the original software. If you use this software 24 | // in a product, an acknowledgment in the product documentation would be 25 | // appreciated but is not required. 26 | // 27 | // 2. Altered source versions must be plainly marked as such, and must not be 28 | // misrepresented as being the original software. 29 | // 30 | // 3. This notice may not be removed or altered from any source distribution. 31 | // 32 | 33 | #import "AutoCoding.h" 34 | #import 35 | 36 | 37 | #pragma clang diagnostic ignored "-Wgnu" 38 | #pragma clang diagnostic ignored "-Wpartial-availability" 39 | #pragma clang diagnostic ignored "-Wobjc-designated-initializers" 40 | 41 | 42 | static NSString *const AutocodingException = @"AutocodingException"; 43 | 44 | 45 | @implementation NSObject (AutoCoding) 46 | 47 | + (BOOL)supportsSecureCoding 48 | { 49 | return YES; 50 | } 51 | 52 | + (instancetype)objectWithContentsOfFile:(NSString *)filePath 53 | { 54 | //load the file 55 | NSData *data = [NSData dataWithContentsOfFile:filePath]; 56 | 57 | //attempt to deserialise data as a plist 58 | id object = nil; 59 | if (data) 60 | { 61 | NSPropertyListFormat format; 62 | object = [NSPropertyListSerialization propertyListWithData:data options:NSPropertyListImmutable format:&format error:NULL]; 63 | 64 | //success? 65 | if (object) 66 | { 67 | //check if object is an NSCoded unarchive 68 | if ([object respondsToSelector:@selector(objectForKeyedSubscript:)] && ((NSDictionary *)object)[@"$archiver"]) 69 | { 70 | object = [NSKeyedUnarchiver unarchiveObjectWithData:data]; 71 | } 72 | } 73 | else 74 | { 75 | //return raw data 76 | object = data; 77 | } 78 | } 79 | 80 | //return object 81 | return object; 82 | } 83 | 84 | - (BOOL)writeToFile:(NSString *)filePath atomically:(BOOL)useAuxiliaryFile 85 | { 86 | //note: NSData, NSDictionary and NSArray already implement this method 87 | //and do not save using NSCoding, however the objectWithContentsOfFile 88 | //method will correctly recover these objects anyway 89 | 90 | //archive object 91 | NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self]; 92 | return [data writeToFile:filePath atomically:useAuxiliaryFile]; 93 | } 94 | 95 | + (NSDictionary *)codableProperties 96 | { 97 | //deprecated 98 | SEL deprecatedSelector = NSSelectorFromString(@"uncodableProperties"); 99 | NSArray *uncodableProperties = nil; 100 | if ([self respondsToSelector:deprecatedSelector] || [self instancesRespondToSelector:deprecatedSelector]) 101 | { 102 | uncodableProperties = [self valueForKey:@"uncodableProperties"]; 103 | NSLog(@"AutoCoding Warning: uncodableProperties method is no longer supported. Use ivars, or synthesize your properties using non-KVC-compliant names to avoid coding them instead."); 104 | } 105 | 106 | unsigned int propertyCount; 107 | __autoreleasing NSMutableDictionary *codableProperties = [NSMutableDictionary dictionary]; 108 | objc_property_t *properties = class_copyPropertyList(self, &propertyCount); 109 | for (unsigned int i = 0; i < propertyCount; i++) 110 | { 111 | //get property name 112 | objc_property_t property = properties[i]; 113 | const char *propertyName = property_getName(property); 114 | __autoreleasing NSString *key = @(propertyName); 115 | 116 | //check if codable 117 | if (![uncodableProperties containsObject:key]) 118 | { 119 | //get property type 120 | Class propertyClass = nil; 121 | char *typeEncoding = property_copyAttributeValue(property, "T"); 122 | switch (typeEncoding[0]) 123 | { 124 | case '@': 125 | { 126 | if (strlen(typeEncoding) >= 3) 127 | { 128 | char *className = strndup(typeEncoding + 2, strlen(typeEncoding) - 3); 129 | __autoreleasing NSString *name = @(className); 130 | NSRange range = [name rangeOfString:@"<"]; 131 | if (range.location != NSNotFound) 132 | { 133 | name = [name substringToIndex:range.location]; 134 | } 135 | propertyClass = NSClassFromString(name) ?: [NSObject class]; 136 | free(className); 137 | } 138 | break; 139 | } 140 | case 'c': 141 | case 'i': 142 | case 's': 143 | case 'l': 144 | case 'q': 145 | case 'C': 146 | case 'I': 147 | case 'S': 148 | case 'L': 149 | case 'Q': 150 | case 'f': 151 | case 'd': 152 | case 'B': 153 | { 154 | propertyClass = [NSNumber class]; 155 | break; 156 | } 157 | case '{': 158 | { 159 | propertyClass = [NSValue class]; 160 | break; 161 | } 162 | } 163 | free(typeEncoding); 164 | 165 | if (propertyClass) 166 | { 167 | //check if there is a backing ivar 168 | char *ivar = property_copyAttributeValue(property, "V"); 169 | if (ivar) 170 | { 171 | //check if ivar has KVC-compliant name 172 | __autoreleasing NSString *ivarName = @(ivar); 173 | if ([ivarName isEqualToString:key] || [ivarName isEqualToString:[@"_" stringByAppendingString:key]]) 174 | { 175 | //no setter, but setValue:forKey: will still work 176 | codableProperties[key] = propertyClass; 177 | } 178 | free(ivar); 179 | } 180 | else 181 | { 182 | //check if property is dynamic and readwrite 183 | char *dynamic = property_copyAttributeValue(property, "D"); 184 | char *readonly = property_copyAttributeValue(property, "R"); 185 | if (dynamic && !readonly) 186 | { 187 | //no ivar, but setValue:forKey: will still work 188 | codableProperties[key] = propertyClass; 189 | } 190 | free(dynamic); 191 | free(readonly); 192 | } 193 | } 194 | } 195 | } 196 | 197 | free(properties); 198 | return codableProperties; 199 | } 200 | 201 | - (NSDictionary *)codableProperties 202 | { 203 | __autoreleasing NSDictionary *codableProperties = objc_getAssociatedObject([self class], _cmd); 204 | if (!codableProperties) 205 | { 206 | codableProperties = [NSMutableDictionary dictionary]; 207 | Class subclass = [self class]; 208 | while (subclass != [NSObject class]) 209 | { 210 | [(NSMutableDictionary *)codableProperties addEntriesFromDictionary:[subclass codableProperties]]; 211 | subclass = [subclass superclass]; 212 | } 213 | codableProperties = [NSDictionary dictionaryWithDictionary:codableProperties]; 214 | 215 | //make the association atomically so that we don't need to bother with an @synchronize 216 | objc_setAssociatedObject([self class], _cmd, codableProperties, OBJC_ASSOCIATION_RETAIN); 217 | } 218 | return codableProperties; 219 | } 220 | 221 | - (NSDictionary *)dictionaryRepresentation 222 | { 223 | NSMutableDictionary *dict = [NSMutableDictionary dictionary]; 224 | for (__unsafe_unretained NSString *key in self.codableProperties) 225 | { 226 | id value = [self valueForKey:key]; 227 | if (value) dict[key] = value; 228 | } 229 | return dict; 230 | } 231 | 232 | - (void)setWithCoder:(NSCoder *)aDecoder 233 | { 234 | BOOL secureAvailable = [aDecoder respondsToSelector:@selector(decodeObjectOfClass:forKey:)]; 235 | BOOL secureSupported = [[self class] supportsSecureCoding]; 236 | NSDictionary *properties = self.codableProperties; 237 | for (NSString *key in properties) 238 | { 239 | id object = nil; 240 | Class propertyClass = properties[key]; 241 | if (secureAvailable) 242 | { 243 | object = [aDecoder decodeObjectOfClass:propertyClass forKey:key]; 244 | } 245 | else 246 | { 247 | object = [aDecoder decodeObjectForKey:key]; 248 | } 249 | if (object) 250 | { 251 | if (secureSupported && ![object isKindOfClass:propertyClass] && object != [NSNull null]) 252 | { 253 | [NSException raise:AutocodingException format:@"Expected '%@' to be a %@, but was actually a %@", key, propertyClass, [object class]]; 254 | } 255 | [self setValue:object forKey:key]; 256 | } 257 | } 258 | } 259 | 260 | - (instancetype)initWithCoder:(NSCoder *)aDecoder 261 | { 262 | [self setWithCoder:aDecoder]; 263 | return self; 264 | } 265 | 266 | - (void)encodeWithCoder:(NSCoder *)aCoder 267 | { 268 | for (NSString *key in self.codableProperties) 269 | { 270 | id object = [self valueForKey:key]; 271 | if (object) [aCoder encodeObject:object forKey:key]; 272 | } 273 | } 274 | 275 | @end 276 | -------------------------------------------------------------------------------- /Examples/AutoTodoList/Classes/NewItemViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // NewItemViewController.h 3 | // TodoList 4 | // 5 | // Created by Nick Lockwood on 15/04/2010. 6 | // Copyright 2010 Charcoal Design. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class TodoItem; 12 | 13 | @interface NewItemViewController : UIViewController 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Examples/AutoTodoList/Classes/NewItemViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // NewItemViewController.m 3 | // TodoList 4 | // 5 | // Created by Nick Lockwood on 15/04/2010. 6 | // Copyright 2010 Charcoal Design. All rights reserved. 7 | // 8 | 9 | #import "NewItemViewController.h" 10 | #import "TodoList.h" 11 | #import "TodoItem.h" 12 | 13 | 14 | @interface NewItemViewController() 15 | 16 | @property (nonatomic, strong) TodoItem *item; 17 | 18 | @end 19 | 20 | 21 | @implementation NewItemViewController 22 | 23 | #pragma mark - 24 | #pragma mark UITextViewDelegate methods 25 | 26 | - (void)textViewDidChange:(UITextView *)textView 27 | { 28 | if (self.item == nil) 29 | { 30 | //create a new TodoItem and add to list 31 | self.item = [TodoItem itemWithLabel:textView.text]; 32 | [[TodoList sharedList].items addObject:self.item]; 33 | } 34 | else 35 | { 36 | //update the TodoItem 37 | self.item.label = textView.text; 38 | } 39 | 40 | //save the TodoList 41 | [[TodoList sharedList] save]; 42 | } 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /Examples/AutoTodoList/Classes/NewItemViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 800 5 | 10D573 6 | 762 7 | 1038.29 8 | 460.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 87 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 | 42 | 274 43 | 44 | YES 45 | 46 | 47 | 274 48 | {320, 460} 49 | 50 | 51 | 1 52 | MSAxIDEAA 53 | 54 | YES 55 | YES 56 | IBCocoaTouchFramework 57 | NO 58 | NO 59 | NO 60 | NO 61 | 62 | 63 | 2 64 | IBCocoaTouchFramework 65 | 66 | 67 | 68 | {320, 460} 69 | 70 | 71 | 3 72 | MQA 73 | 74 | 2 75 | 76 | 77 | 78 | IBCocoaTouchFramework 79 | 80 | 81 | 82 | 83 | YES 84 | 85 | 86 | view 87 | 88 | 89 | 90 | 3 91 | 92 | 93 | 94 | delegate 95 | 96 | 97 | 98 | 8 99 | 100 | 101 | 102 | 103 | YES 104 | 105 | 0 106 | 107 | 108 | 109 | 110 | 111 | 1 112 | 113 | 114 | YES 115 | 116 | 117 | 118 | 119 | 120 | -1 121 | 122 | 123 | File's Owner 124 | 125 | 126 | -2 127 | 128 | 129 | 130 | 131 | 7 132 | 133 | 134 | 135 | 136 | 137 | 138 | YES 139 | 140 | YES 141 | -1.CustomClassName 142 | -2.CustomClassName 143 | 1.IBEditorWindowLastContentRect 144 | 1.IBPluginDependency 145 | 7.IBPluginDependency 146 | 147 | 148 | YES 149 | NewItemViewController 150 | UIResponder 151 | {{556, 412}, {320, 480}} 152 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 153 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 154 | 155 | 156 | 157 | YES 158 | 159 | 160 | YES 161 | 162 | 163 | 164 | 165 | YES 166 | 167 | 168 | YES 169 | 170 | 171 | 172 | 8 173 | 174 | 175 | 176 | YES 177 | 178 | NewItemViewController 179 | UIViewController 180 | 181 | IBProjectSource 182 | Classes/NewItemViewController.h 183 | 184 | 185 | 186 | 187 | YES 188 | 189 | NSObject 190 | 191 | IBFrameworkSource 192 | Foundation.framework/Headers/NSError.h 193 | 194 | 195 | 196 | NSObject 197 | 198 | IBFrameworkSource 199 | Foundation.framework/Headers/NSFileManager.h 200 | 201 | 202 | 203 | NSObject 204 | 205 | IBFrameworkSource 206 | Foundation.framework/Headers/NSKeyValueCoding.h 207 | 208 | 209 | 210 | NSObject 211 | 212 | IBFrameworkSource 213 | Foundation.framework/Headers/NSKeyValueObserving.h 214 | 215 | 216 | 217 | NSObject 218 | 219 | IBFrameworkSource 220 | Foundation.framework/Headers/NSKeyedArchiver.h 221 | 222 | 223 | 224 | NSObject 225 | 226 | IBFrameworkSource 227 | Foundation.framework/Headers/NSNetServices.h 228 | 229 | 230 | 231 | NSObject 232 | 233 | IBFrameworkSource 234 | Foundation.framework/Headers/NSObject.h 235 | 236 | 237 | 238 | NSObject 239 | 240 | IBFrameworkSource 241 | Foundation.framework/Headers/NSPort.h 242 | 243 | 244 | 245 | NSObject 246 | 247 | IBFrameworkSource 248 | Foundation.framework/Headers/NSRunLoop.h 249 | 250 | 251 | 252 | NSObject 253 | 254 | IBFrameworkSource 255 | Foundation.framework/Headers/NSStream.h 256 | 257 | 258 | 259 | NSObject 260 | 261 | IBFrameworkSource 262 | Foundation.framework/Headers/NSThread.h 263 | 264 | 265 | 266 | NSObject 267 | 268 | IBFrameworkSource 269 | Foundation.framework/Headers/NSURL.h 270 | 271 | 272 | 273 | NSObject 274 | 275 | IBFrameworkSource 276 | Foundation.framework/Headers/NSURLConnection.h 277 | 278 | 279 | 280 | NSObject 281 | 282 | IBFrameworkSource 283 | Foundation.framework/Headers/NSXMLParser.h 284 | 285 | 286 | 287 | NSObject 288 | 289 | IBFrameworkSource 290 | UIKit.framework/Headers/UIAccessibility.h 291 | 292 | 293 | 294 | NSObject 295 | 296 | IBFrameworkSource 297 | UIKit.framework/Headers/UINibLoading.h 298 | 299 | 300 | 301 | NSObject 302 | 303 | IBFrameworkSource 304 | UIKit.framework/Headers/UIResponder.h 305 | 306 | 307 | 308 | UIResponder 309 | NSObject 310 | 311 | 312 | 313 | UIScrollView 314 | UIView 315 | 316 | IBFrameworkSource 317 | UIKit.framework/Headers/UIScrollView.h 318 | 319 | 320 | 321 | UISearchBar 322 | UIView 323 | 324 | IBFrameworkSource 325 | UIKit.framework/Headers/UISearchBar.h 326 | 327 | 328 | 329 | UISearchDisplayController 330 | NSObject 331 | 332 | IBFrameworkSource 333 | UIKit.framework/Headers/UISearchDisplayController.h 334 | 335 | 336 | 337 | UITextView 338 | UIScrollView 339 | 340 | IBFrameworkSource 341 | UIKit.framework/Headers/UITextView.h 342 | 343 | 344 | 345 | UIView 346 | 347 | IBFrameworkSource 348 | UIKit.framework/Headers/UITextField.h 349 | 350 | 351 | 352 | UIView 353 | UIResponder 354 | 355 | IBFrameworkSource 356 | UIKit.framework/Headers/UIView.h 357 | 358 | 359 | 360 | UIViewController 361 | 362 | IBFrameworkSource 363 | UIKit.framework/Headers/UINavigationController.h 364 | 365 | 366 | 367 | UIViewController 368 | 369 | IBFrameworkSource 370 | UIKit.framework/Headers/UITabBarController.h 371 | 372 | 373 | 374 | UIViewController 375 | UIResponder 376 | 377 | IBFrameworkSource 378 | UIKit.framework/Headers/UIViewController.h 379 | 380 | 381 | 382 | 383 | 0 384 | IBCocoaTouchFramework 385 | 386 | com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 387 | 388 | 389 | YES 390 | ../TodoList4.xcodeproj 391 | 3 392 | 87 393 | 394 | 395 | -------------------------------------------------------------------------------- /Examples/AutoTodoList/Classes/TodoItem.h: -------------------------------------------------------------------------------- 1 | // 2 | // TodoItem.h 3 | // TodoList 4 | // 5 | // Created by Nick Lockwood on 08/04/2010. 6 | // Copyright 2010 Charcoal Design. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface TodoItem : NSObject 13 | 14 | + (TodoItem *)itemWithLabel:(NSString *)label; 15 | 16 | @property (nonatomic, strong) NSString *label; 17 | @property (nonatomic, assign) BOOL checked; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /Examples/AutoTodoList/Classes/TodoItem.m: -------------------------------------------------------------------------------- 1 | // 2 | // TodoItem.m 3 | // TodoList 4 | // 5 | // Created by Nick Lockwood on 08/04/2010. 6 | // Copyright 2010 Charcoal Design. All rights reserved. 7 | // 8 | 9 | #import "TodoItem.h" 10 | 11 | 12 | @implementation TodoItem 13 | 14 | + (TodoItem *)itemWithLabel:(NSString *)label 15 | { 16 | TodoItem *item = [[self alloc] init]; 17 | item.label = label; 18 | return item; 19 | } 20 | 21 | #pragma mark - 22 | #pragma mark NSCoding 23 | 24 | //note: we've not implemented the NSCoding methods 25 | //because the AutoCoding library takes care of this for us 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /Examples/AutoTodoList/Classes/TodoList.h: -------------------------------------------------------------------------------- 1 | // 2 | // TodoList.h 3 | // TodoList 4 | // 5 | // Created by Nick Lockwood on 15/04/2010. 6 | // Copyright 2010 Charcoal Design. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface TodoList : NSObject 13 | 14 | @property (nonatomic, strong) NSMutableArray *items; 15 | 16 | + (TodoList *)sharedList; 17 | - (void)save; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /Examples/AutoTodoList/Classes/TodoList.m: -------------------------------------------------------------------------------- 1 | // 2 | // TodoList.m 3 | // TodoList 4 | // 5 | // Created by Nick Lockwood on 15/04/2010. 6 | // Copyright 2010 Charcoal Design. All rights reserved. 7 | // 8 | 9 | #import "TodoList.h" 10 | #import "TodoItem.h" 11 | #import "HRCoder.h" 12 | 13 | 14 | @implementation TodoList 15 | 16 | #pragma mark - 17 | #pragma mark Loading and saving 18 | 19 | + (NSString *)documentsDirectory 20 | { 21 | return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; 22 | } 23 | 24 | + (TodoList *)sharedList 25 | { 26 | static TodoList *sharedList = nil; 27 | if (sharedList == nil) 28 | { 29 | //attempt to load saved file 30 | NSString *path = [[self documentsDirectory] stringByAppendingPathComponent:@"TodoList.plist"]; 31 | sharedList = [HRCoder unarchiveObjectWithFile:path]; 32 | 33 | //if that fails, load default list from bundle 34 | if (sharedList == nil) 35 | { 36 | path = [[NSBundle mainBundle] pathForResource:@"TodoList" ofType:@"plist"]; 37 | sharedList = [HRCoder unarchiveObjectWithFile:path]; 38 | } 39 | } 40 | return sharedList; 41 | } 42 | 43 | - (void)save 44 | { 45 | NSString *path = [[[self class] documentsDirectory] stringByAppendingPathComponent:@"TodoList.plist"]; 46 | [HRCoder archiveRootObject:self toFile:path]; 47 | } 48 | 49 | #pragma mark - 50 | #pragma mark NSCoding 51 | 52 | //note: we've not implemented the NSCoding methods 53 | //because the AutoCoding library takes care of this for us 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /Examples/AutoTodoList/Classes/TodoListAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // TodoListAppDelegate.h 3 | // TodoList 4 | // 5 | // Created by Nick Lockwood on 08/04/2010. 6 | // Copyright Charcoal Design 2010. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface TodoListAppDelegate : NSObject 12 | 13 | @property (nonatomic, strong) IBOutlet UIWindow *window; 14 | @property (nonatomic, strong) IBOutlet UINavigationController *viewController; 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /Examples/AutoTodoList/Classes/TodoListAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // TodoListAppDelegate.m 3 | // TodoList 4 | // 5 | // Created by Nick Lockwood on 08/04/2010. 6 | // Copyright Charcoal Design 2010. All rights reserved. 7 | // 8 | 9 | #import "TodoListAppDelegate.h" 10 | #import "TodoListViewController.h" 11 | 12 | 13 | @implementation TodoListAppDelegate 14 | 15 | - (void)applicationDidFinishLaunching:(__unused UIApplication *)application 16 | { 17 | // Override point for customization after app launch 18 | [self.window addSubview:self.viewController.view]; 19 | [self.window makeKeyAndVisible]; 20 | } 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /Examples/AutoTodoList/Classes/TodoListViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // TodoList1ViewController.h 3 | // TodoList1 4 | // 5 | // Created by Nick Lockwood on 08/04/2010. 6 | // Copyright Charcoal Design 2010. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface TodoListViewController : UIViewController 12 | 13 | @property (nonatomic, strong) IBOutlet UITableView *tableView; 14 | 15 | - (IBAction)toggleEditing:(id)sender; 16 | - (IBAction)createNewItem; 17 | 18 | @end 19 | 20 | -------------------------------------------------------------------------------- /Examples/AutoTodoList/Classes/TodoListViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // TodoListViewController.m 3 | // TodoList 4 | // 5 | // Created by Nick Lockwood on 08/04/2010. 6 | // Copyright Charcoal Design 2010. All rights reserved. 7 | // 8 | 9 | #import "TodoListViewController.h" 10 | #import "NewItemViewController.h" 11 | #import "TodoItem.h" 12 | #import "TodoList.h" 13 | 14 | 15 | @implementation TodoListViewController 16 | 17 | - (void)viewDidAppear:(BOOL)animated 18 | { 19 | [super viewDidAppear:animated]; 20 | [self.tableView reloadData]; 21 | } 22 | 23 | - (IBAction)toggleEditing:(id)sender 24 | { 25 | [self.tableView setEditing:!self.tableView.editing animated:YES]; 26 | [sender setTitle:(self.tableView.editing)? @"Done" : @"Edit"]; 27 | } 28 | 29 | - (IBAction)createNewItem 30 | { 31 | UIViewController *viewController = [[NewItemViewController alloc] init]; 32 | [self.navigationController pushViewController:viewController animated:YES]; 33 | } 34 | 35 | #pragma mark - 36 | #pragma mark UITableViewDelegate methods 37 | 38 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 39 | { 40 | TodoItem *item = [TodoList sharedList].items[(NSUInteger)indexPath.row]; 41 | item.checked = !item.checked; 42 | [[TodoList sharedList] save]; 43 | [tableView reloadData]; 44 | } 45 | 46 | - (UITableViewCellEditingStyle)tableView:(__unused UITableView *)tableView editingStyleForRowAtIndexPath:(__unused NSIndexPath *)indexPath 47 | { 48 | return UITableViewCellEditingStyleDelete; 49 | } 50 | 51 | - (void)tableView:(__unused UITableView *)tableView commitEditingStyle:(__unused UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath 52 | { 53 | [[TodoList sharedList].items removeObjectAtIndex:(NSUInteger)indexPath.row]; 54 | [[TodoList sharedList] save]; 55 | [self.tableView reloadData]; 56 | } 57 | 58 | #pragma mark - 59 | #pragma mark UITableViewDataSource methods 60 | 61 | - (NSInteger)tableView:(__unused UITableView *)table numberOfRowsInSection:(__unused NSInteger)section 62 | { 63 | return (NSInteger)[[TodoList sharedList].items count]; 64 | } 65 | 66 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 67 | { 68 | static NSString *cellType = @"Cell"; 69 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellType]; 70 | if (cell == nil) 71 | { 72 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellType]; 73 | } 74 | 75 | TodoItem *item = [TodoList sharedList].items[(NSUInteger)indexPath.row]; 76 | cell.textLabel.text = item.label; 77 | cell.accessoryType = item.checked? UITableViewCellAccessoryCheckmark: UITableViewCellAccessoryNone; 78 | 79 | return cell; 80 | } 81 | 82 | @end 83 | -------------------------------------------------------------------------------- /Examples/AutoTodoList/Classes/TodoListViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1296 5 | 11D50 6 | 2182 7 | 1138.32 8 | 568.00 9 | 10 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 11 | 1181 12 | 13 | 14 | YES 15 | IBProxyObject 16 | IBUIView 17 | IBUITableView 18 | 19 | 20 | YES 21 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 22 | 23 | 24 | PluginDependencyRecalculationVersion 25 | 26 | 27 | 28 | YES 29 | 30 | IBFilesOwner 31 | IBCocoaTouchFramework 32 | 33 | 34 | IBFirstResponder 35 | IBCocoaTouchFramework 36 | 37 | 38 | 39 | 274 40 | 41 | YES 42 | 43 | 44 | 274 45 | {320, 460} 46 | 47 | 48 | 49 | 50 | 3 51 | MQA 52 | 53 | NO 54 | YES 55 | NO 56 | IBCocoaTouchFramework 57 | NO 58 | 1 59 | 0 60 | YES 61 | 44 62 | 22 63 | 22 64 | 65 | 66 | {{0, 20}, {320, 460}} 67 | 68 | 69 | 70 | 71 | 3 72 | MC43NQA 73 | 74 | 2 75 | 76 | 77 | NO 78 | 79 | IBCocoaTouchFramework 80 | 81 | 82 | 83 | 84 | YES 85 | 86 | 87 | tableView 88 | 89 | 90 | 91 | 17 92 | 93 | 94 | 95 | view 96 | 97 | 98 | 99 | 18 100 | 101 | 102 | 103 | dataSource 104 | 105 | 106 | 107 | 15 108 | 109 | 110 | 111 | delegate 112 | 113 | 114 | 115 | 16 116 | 117 | 118 | 119 | 120 | YES 121 | 122 | 0 123 | 124 | YES 125 | 126 | 127 | 128 | 129 | 130 | -1 131 | 132 | 133 | File's Owner 134 | 135 | 136 | -2 137 | 138 | 139 | 140 | 141 | 6 142 | 143 | 144 | YES 145 | 146 | 147 | 148 | 149 | 150 | 8 151 | 152 | 153 | 154 | 155 | 156 | 157 | YES 158 | 159 | YES 160 | -1.CustomClassName 161 | -1.IBPluginDependency 162 | -2.CustomClassName 163 | -2.IBPluginDependency 164 | 6.IBPluginDependency 165 | 8.IBPluginDependency 166 | 167 | 168 | YES 169 | TodoListViewController 170 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 171 | UIResponder 172 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 173 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 174 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin 175 | 176 | 177 | 178 | YES 179 | 180 | 181 | 182 | 183 | 184 | YES 185 | 186 | 187 | 188 | 189 | 18 190 | 191 | 192 | 0 193 | IBCocoaTouchFramework 194 | 195 | com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS 196 | 197 | 198 | 199 | com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3 200 | 201 | 202 | YES 203 | 3 204 | 1181 205 | 206 | 207 | -------------------------------------------------------------------------------- /Examples/AutoTodoList/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicklockwood/HRCoder/758a58f47bc36260b6d8df4c84c962e30f944527/Examples/AutoTodoList/Default-568h@2x.png -------------------------------------------------------------------------------- /Examples/AutoTodoList/HRAutoTodoList-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIconFile 12 | 13 | CFBundleIdentifier 14 | $(PRODUCT_BUNDLE_IDENTIFIER) 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | ${PRODUCT_NAME} 19 | CFBundlePackageType 20 | APPL 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | NSMainNibFile 28 | MainWindow 29 | 30 | 31 | -------------------------------------------------------------------------------- /Examples/AutoTodoList/HRAutoTodoList.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 012EAFC4116E25680023862F /* TodoItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 012EAFC3116E25680023862F /* TodoItem.m */; }; 11 | 01457AEB117723E2005BBF82 /* NewItemViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 01457AE9117723E2005BBF82 /* NewItemViewController.m */; }; 12 | 01457AEC117723E2005BBF82 /* NewItemViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 01457AEA117723E2005BBF82 /* NewItemViewController.xib */; }; 13 | 01457AF2117724D1005BBF82 /* TodoList.m in Sources */ = {isa = PBXBuildFile; fileRef = 01457AF1117724D1005BBF82 /* TodoList.m */; }; 14 | 019951281611F7460092AC63 /* AutoCoding.m in Sources */ = {isa = PBXBuildFile; fileRef = 019951271611F7460092AC63 /* AutoCoding.m */; }; 15 | 01CDB2361611A55900B929AD /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 01CDB2351611A55900B929AD /* Default-568h@2x.png */; }; 16 | 1D3623260D0F684500981E51 /* TodoListAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D3623250D0F684500981E51 /* TodoListAppDelegate.m */; }; 17 | 1D60589B0D05DD56006BFB54 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; }; 18 | 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; 19 | 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; }; 20 | 288765A50DF7441C002DB57D /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288765A40DF7441C002DB57D /* CoreGraphics.framework */; }; 21 | 28AD733F0D9D9553002E5188 /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 28AD733E0D9D9553002E5188 /* MainWindow.xib */; }; 22 | 28D7ACF80DDB3853001CB0EB /* TodoListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 28D7ACF70DDB3853001CB0EB /* TodoListViewController.m */; }; 23 | B2E4C05B155145E600219D16 /* TodoListViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = B2E4C05A155145E600219D16 /* TodoListViewController.xib */; }; 24 | B2E4C0631551494600219D16 /* HRCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = B2E4C0621551494600219D16 /* HRCoder.m */; }; 25 | B2E4C066155149FF00219D16 /* TodoList.plist in Resources */ = {isa = PBXBuildFile; fileRef = B2E4C065155149FF00219D16 /* TodoList.plist */; }; 26 | /* End PBXBuildFile section */ 27 | 28 | /* Begin PBXFileReference section */ 29 | 012EAFC2116E25680023862F /* TodoItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TodoItem.h; sourceTree = ""; }; 30 | 012EAFC3116E25680023862F /* TodoItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TodoItem.m; sourceTree = ""; }; 31 | 01457AE8117723E2005BBF82 /* NewItemViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NewItemViewController.h; sourceTree = ""; }; 32 | 01457AE9117723E2005BBF82 /* NewItemViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NewItemViewController.m; sourceTree = ""; }; 33 | 01457AEA117723E2005BBF82 /* NewItemViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = NewItemViewController.xib; path = Classes/NewItemViewController.xib; sourceTree = ""; }; 34 | 01457AF0117724D1005BBF82 /* TodoList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TodoList.h; sourceTree = ""; }; 35 | 01457AF1117724D1005BBF82 /* TodoList.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TodoList.m; sourceTree = ""; }; 36 | 019951261611F7460092AC63 /* AutoCoding.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AutoCoding.h; sourceTree = ""; }; 37 | 019951271611F7460092AC63 /* AutoCoding.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AutoCoding.m; sourceTree = ""; }; 38 | 01CDB2351611A55900B929AD /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; 39 | 1D30AB110D05D00D00671497 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 40 | 1D3623240D0F684500981E51 /* TodoListAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TodoListAppDelegate.h; sourceTree = ""; }; 41 | 1D3623250D0F684500981E51 /* TodoListAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TodoListAppDelegate.m; sourceTree = ""; }; 42 | 1D6058910D05DD3D006BFB54 /* HRAutoTodoList.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HRAutoTodoList.app; sourceTree = BUILT_PRODUCTS_DIR; }; 43 | 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 44 | 288765A40DF7441C002DB57D /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 45 | 28AD733E0D9D9553002E5188 /* MainWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MainWindow.xib; sourceTree = ""; }; 46 | 28D7ACF60DDB3853001CB0EB /* TodoListViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TodoListViewController.h; sourceTree = ""; }; 47 | 28D7ACF70DDB3853001CB0EB /* TodoListViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TodoListViewController.m; sourceTree = ""; }; 48 | 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 49 | 32CA4F630368D1EE00C91783 /* HRAutoTodoList_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HRAutoTodoList_Prefix.pch; sourceTree = ""; }; 50 | 8D1107310486CEB800E47090 /* HRAutoTodoList-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "HRAutoTodoList-Info.plist"; plistStructureDefinitionIdentifier = "com.apple.xcode.plist.structure-definition.iphone.info-plist"; sourceTree = ""; }; 51 | B2E4C05A155145E600219D16 /* TodoListViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = TodoListViewController.xib; path = Classes/TodoListViewController.xib; sourceTree = ""; }; 52 | B2E4C0611551494600219D16 /* HRCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HRCoder.h; sourceTree = ""; }; 53 | B2E4C0621551494600219D16 /* HRCoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HRCoder.m; sourceTree = ""; }; 54 | B2E4C065155149FF00219D16 /* TodoList.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = TodoList.plist; sourceTree = ""; }; 55 | /* End PBXFileReference section */ 56 | 57 | /* Begin PBXFrameworksBuildPhase section */ 58 | 1D60588F0D05DD3D006BFB54 /* Frameworks */ = { 59 | isa = PBXFrameworksBuildPhase; 60 | buildActionMask = 2147483647; 61 | files = ( 62 | 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */, 63 | 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */, 64 | 288765A50DF7441C002DB57D /* CoreGraphics.framework in Frameworks */, 65 | ); 66 | runOnlyForDeploymentPostprocessing = 0; 67 | }; 68 | /* End PBXFrameworksBuildPhase section */ 69 | 70 | /* Begin PBXGroup section */ 71 | 01457AF311772690005BBF82 /* View Controllers */ = { 72 | isa = PBXGroup; 73 | children = ( 74 | 1D3623240D0F684500981E51 /* TodoListAppDelegate.h */, 75 | 1D3623250D0F684500981E51 /* TodoListAppDelegate.m */, 76 | 28D7ACF60DDB3853001CB0EB /* TodoListViewController.h */, 77 | 28D7ACF70DDB3853001CB0EB /* TodoListViewController.m */, 78 | 01457AE8117723E2005BBF82 /* NewItemViewController.h */, 79 | 01457AE9117723E2005BBF82 /* NewItemViewController.m */, 80 | ); 81 | name = "View Controllers"; 82 | sourceTree = ""; 83 | }; 84 | 01457AF41177269B005BBF82 /* Model */ = { 85 | isa = PBXGroup; 86 | children = ( 87 | 012EAFC2116E25680023862F /* TodoItem.h */, 88 | 012EAFC3116E25680023862F /* TodoItem.m */, 89 | 01457AF0117724D1005BBF82 /* TodoList.h */, 90 | 01457AF1117724D1005BBF82 /* TodoList.m */, 91 | ); 92 | name = Model; 93 | sourceTree = ""; 94 | }; 95 | 080E96DDFE201D6D7F000001 /* Classes */ = { 96 | isa = PBXGroup; 97 | children = ( 98 | 01457AF311772690005BBF82 /* View Controllers */, 99 | 01457AF41177269B005BBF82 /* Model */, 100 | ); 101 | path = Classes; 102 | sourceTree = ""; 103 | }; 104 | 19C28FACFE9D520D11CA2CBB /* Products */ = { 105 | isa = PBXGroup; 106 | children = ( 107 | 1D6058910D05DD3D006BFB54 /* HRAutoTodoList.app */, 108 | ); 109 | name = Products; 110 | sourceTree = ""; 111 | }; 112 | 29B97314FDCFA39411CA2CEA /* CustomTemplate */ = { 113 | isa = PBXGroup; 114 | children = ( 115 | B2E4C06B15514DE700219D16 /* AutoCoding */, 116 | B2E4C0601551494600219D16 /* HRCoder */, 117 | 080E96DDFE201D6D7F000001 /* Classes */, 118 | 29B97315FDCFA39411CA2CEA /* Other Sources */, 119 | 29B97317FDCFA39411CA2CEA /* Resources */, 120 | 29B97323FDCFA39411CA2CEA /* Frameworks */, 121 | 19C28FACFE9D520D11CA2CBB /* Products */, 122 | ); 123 | name = CustomTemplate; 124 | sourceTree = ""; 125 | }; 126 | 29B97315FDCFA39411CA2CEA /* Other Sources */ = { 127 | isa = PBXGroup; 128 | children = ( 129 | 32CA4F630368D1EE00C91783 /* HRAutoTodoList_Prefix.pch */, 130 | 29B97316FDCFA39411CA2CEA /* main.m */, 131 | ); 132 | name = "Other Sources"; 133 | sourceTree = ""; 134 | }; 135 | 29B97317FDCFA39411CA2CEA /* Resources */ = { 136 | isa = PBXGroup; 137 | children = ( 138 | 01CDB2351611A55900B929AD /* Default-568h@2x.png */, 139 | B2E4C05A155145E600219D16 /* TodoListViewController.xib */, 140 | 01457AEA117723E2005BBF82 /* NewItemViewController.xib */, 141 | 28AD733E0D9D9553002E5188 /* MainWindow.xib */, 142 | 8D1107310486CEB800E47090 /* HRAutoTodoList-Info.plist */, 143 | B2E4C065155149FF00219D16 /* TodoList.plist */, 144 | ); 145 | name = Resources; 146 | sourceTree = ""; 147 | }; 148 | 29B97323FDCFA39411CA2CEA /* Frameworks */ = { 149 | isa = PBXGroup; 150 | children = ( 151 | 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */, 152 | 1D30AB110D05D00D00671497 /* Foundation.framework */, 153 | 288765A40DF7441C002DB57D /* CoreGraphics.framework */, 154 | ); 155 | name = Frameworks; 156 | sourceTree = ""; 157 | }; 158 | B2E4C0601551494600219D16 /* HRCoder */ = { 159 | isa = PBXGroup; 160 | children = ( 161 | B2E4C0611551494600219D16 /* HRCoder.h */, 162 | B2E4C0621551494600219D16 /* HRCoder.m */, 163 | ); 164 | name = HRCoder; 165 | path = ../../HRCoder; 166 | sourceTree = ""; 167 | }; 168 | B2E4C06B15514DE700219D16 /* AutoCoding */ = { 169 | isa = PBXGroup; 170 | children = ( 171 | 019951261611F7460092AC63 /* AutoCoding.h */, 172 | 019951271611F7460092AC63 /* AutoCoding.m */, 173 | ); 174 | path = AutoCoding; 175 | sourceTree = ""; 176 | }; 177 | /* End PBXGroup section */ 178 | 179 | /* Begin PBXNativeTarget section */ 180 | 1D6058900D05DD3D006BFB54 /* HRAutoTodoList */ = { 181 | isa = PBXNativeTarget; 182 | buildConfigurationList = 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "HRAutoTodoList" */; 183 | buildPhases = ( 184 | 1D60588D0D05DD3D006BFB54 /* Resources */, 185 | 1D60588E0D05DD3D006BFB54 /* Sources */, 186 | 1D60588F0D05DD3D006BFB54 /* Frameworks */, 187 | ); 188 | buildRules = ( 189 | ); 190 | dependencies = ( 191 | ); 192 | name = HRAutoTodoList; 193 | productName = HRTodoList; 194 | productReference = 1D6058910D05DD3D006BFB54 /* HRAutoTodoList.app */; 195 | productType = "com.apple.product-type.application"; 196 | }; 197 | /* End PBXNativeTarget section */ 198 | 199 | /* Begin PBXProject section */ 200 | 29B97313FDCFA39411CA2CEA /* Project object */ = { 201 | isa = PBXProject; 202 | attributes = { 203 | LastUpgradeCheck = 0900; 204 | }; 205 | buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "HRAutoTodoList" */; 206 | compatibilityVersion = "Xcode 3.2"; 207 | developmentRegion = English; 208 | hasScannedForEncodings = 1; 209 | knownRegions = ( 210 | English, 211 | Japanese, 212 | French, 213 | German, 214 | ); 215 | mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */; 216 | projectDirPath = ""; 217 | projectRoot = ""; 218 | targets = ( 219 | 1D6058900D05DD3D006BFB54 /* HRAutoTodoList */, 220 | ); 221 | }; 222 | /* End PBXProject section */ 223 | 224 | /* Begin PBXResourcesBuildPhase section */ 225 | 1D60588D0D05DD3D006BFB54 /* Resources */ = { 226 | isa = PBXResourcesBuildPhase; 227 | buildActionMask = 2147483647; 228 | files = ( 229 | 28AD733F0D9D9553002E5188 /* MainWindow.xib in Resources */, 230 | 01457AEC117723E2005BBF82 /* NewItemViewController.xib in Resources */, 231 | B2E4C05B155145E600219D16 /* TodoListViewController.xib in Resources */, 232 | B2E4C066155149FF00219D16 /* TodoList.plist in Resources */, 233 | 01CDB2361611A55900B929AD /* Default-568h@2x.png in Resources */, 234 | ); 235 | runOnlyForDeploymentPostprocessing = 0; 236 | }; 237 | /* End PBXResourcesBuildPhase section */ 238 | 239 | /* Begin PBXSourcesBuildPhase section */ 240 | 1D60588E0D05DD3D006BFB54 /* Sources */ = { 241 | isa = PBXSourcesBuildPhase; 242 | buildActionMask = 2147483647; 243 | files = ( 244 | 1D60589B0D05DD56006BFB54 /* main.m in Sources */, 245 | 1D3623260D0F684500981E51 /* TodoListAppDelegate.m in Sources */, 246 | 28D7ACF80DDB3853001CB0EB /* TodoListViewController.m in Sources */, 247 | 012EAFC4116E25680023862F /* TodoItem.m in Sources */, 248 | 01457AEB117723E2005BBF82 /* NewItemViewController.m in Sources */, 249 | 01457AF2117724D1005BBF82 /* TodoList.m in Sources */, 250 | B2E4C0631551494600219D16 /* HRCoder.m in Sources */, 251 | 019951281611F7460092AC63 /* AutoCoding.m in Sources */, 252 | ); 253 | runOnlyForDeploymentPostprocessing = 0; 254 | }; 255 | /* End PBXSourcesBuildPhase section */ 256 | 257 | /* Begin XCBuildConfiguration section */ 258 | 1D6058940D05DD3E006BFB54 /* Debug */ = { 259 | isa = XCBuildConfiguration; 260 | buildSettings = { 261 | ALWAYS_SEARCH_USER_PATHS = NO; 262 | CLANG_ENABLE_OBJC_ARC = YES; 263 | COPY_PHASE_STRIP = NO; 264 | GCC_DYNAMIC_NO_PIC = NO; 265 | GCC_OPTIMIZATION_LEVEL = 0; 266 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 267 | GCC_PREFIX_HEADER = HRAutoTodoList_Prefix.pch; 268 | INFOPLIST_FILE = "HRAutoTodoList-Info.plist"; 269 | PRODUCT_BUNDLE_IDENTIFIER = "com.yourcompany.${PRODUCT_NAME:rfc1034identifier}"; 270 | PRODUCT_NAME = HRAutoTodoList; 271 | SDKROOT = iphoneos; 272 | }; 273 | name = Debug; 274 | }; 275 | 1D6058950D05DD3E006BFB54 /* Release */ = { 276 | isa = XCBuildConfiguration; 277 | buildSettings = { 278 | ALWAYS_SEARCH_USER_PATHS = NO; 279 | CLANG_ENABLE_OBJC_ARC = YES; 280 | COPY_PHASE_STRIP = YES; 281 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 282 | GCC_PREFIX_HEADER = HRAutoTodoList_Prefix.pch; 283 | INFOPLIST_FILE = "HRAutoTodoList-Info.plist"; 284 | PRODUCT_BUNDLE_IDENTIFIER = "com.yourcompany.${PRODUCT_NAME:rfc1034identifier}"; 285 | PRODUCT_NAME = HRAutoTodoList; 286 | SDKROOT = iphoneos; 287 | }; 288 | name = Release; 289 | }; 290 | C01FCF4F08A954540054247B /* Debug */ = { 291 | isa = XCBuildConfiguration; 292 | buildSettings = { 293 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 294 | CLANG_WARN_ASSIGN_ENUM = YES; 295 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 296 | CLANG_WARN_BOOL_CONVERSION = YES; 297 | CLANG_WARN_COMMA = YES; 298 | CLANG_WARN_CONSTANT_CONVERSION = YES; 299 | CLANG_WARN_CXX0X_EXTENSIONS = YES; 300 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 301 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 302 | CLANG_WARN_EMPTY_BODY = YES; 303 | CLANG_WARN_ENUM_CONVERSION = YES; 304 | CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; 305 | CLANG_WARN_INFINITE_RECURSION = YES; 306 | CLANG_WARN_INT_CONVERSION = YES; 307 | CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES; 308 | CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; 309 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 310 | CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = YES; 311 | CLANG_WARN_OBJC_RECEIVER_WEAK = YES; 312 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES; 313 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 314 | CLANG_WARN_STRICT_PROTOTYPES = YES; 315 | CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; 316 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 317 | CLANG_WARN_UNREACHABLE_CODE = YES; 318 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 319 | CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES; 320 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 321 | ENABLE_STRICT_OBJC_MSGSEND = YES; 322 | ENABLE_TESTABILITY = YES; 323 | GCC_C_LANGUAGE_STANDARD = c99; 324 | GCC_NO_COMMON_BLOCKS = YES; 325 | GCC_SHORT_ENUMS = YES; 326 | GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; 327 | GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; 328 | GCC_TREAT_WARNINGS_AS_ERRORS = YES; 329 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 330 | GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; 331 | GCC_WARN_ABOUT_MISSING_NEWLINE = YES; 332 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; 333 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 334 | GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES; 335 | GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES; 336 | GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; 337 | GCC_WARN_MULTIPLE_DEFINITION_TYPES_FOR_SELECTOR = YES; 338 | GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; 339 | GCC_WARN_PEDANTIC = YES; 340 | GCC_WARN_SHADOW = YES; 341 | GCC_WARN_SIGN_COMPARE = YES; 342 | GCC_WARN_STRICT_SELECTOR_MATCH = YES; 343 | GCC_WARN_UNDECLARED_SELECTOR = YES; 344 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 345 | GCC_WARN_UNKNOWN_PRAGMAS = YES; 346 | GCC_WARN_UNUSED_FUNCTION = YES; 347 | GCC_WARN_UNUSED_LABEL = YES; 348 | GCC_WARN_UNUSED_PARAMETER = YES; 349 | GCC_WARN_UNUSED_VARIABLE = YES; 350 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 351 | ONLY_ACTIVE_ARCH = YES; 352 | RUN_CLANG_STATIC_ANALYZER = YES; 353 | SDKROOT = iphoneos; 354 | WARNING_CFLAGS = ( 355 | "-Weverything", 356 | "-Wno-objc-missing-property-synthesis", 357 | ); 358 | }; 359 | name = Debug; 360 | }; 361 | C01FCF5008A954540054247B /* Release */ = { 362 | isa = XCBuildConfiguration; 363 | buildSettings = { 364 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 365 | CLANG_WARN_ASSIGN_ENUM = YES; 366 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 367 | CLANG_WARN_BOOL_CONVERSION = YES; 368 | CLANG_WARN_COMMA = YES; 369 | CLANG_WARN_CONSTANT_CONVERSION = YES; 370 | CLANG_WARN_CXX0X_EXTENSIONS = YES; 371 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 372 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 373 | CLANG_WARN_EMPTY_BODY = YES; 374 | CLANG_WARN_ENUM_CONVERSION = YES; 375 | CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; 376 | CLANG_WARN_INFINITE_RECURSION = YES; 377 | CLANG_WARN_INT_CONVERSION = YES; 378 | CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES; 379 | CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; 380 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 381 | CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = YES; 382 | CLANG_WARN_OBJC_RECEIVER_WEAK = YES; 383 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES; 384 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 385 | CLANG_WARN_STRICT_PROTOTYPES = YES; 386 | CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; 387 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 388 | CLANG_WARN_UNREACHABLE_CODE = YES; 389 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 390 | CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES; 391 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 392 | ENABLE_STRICT_OBJC_MSGSEND = YES; 393 | GCC_C_LANGUAGE_STANDARD = c99; 394 | GCC_NO_COMMON_BLOCKS = YES; 395 | GCC_SHORT_ENUMS = YES; 396 | GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; 397 | GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; 398 | GCC_TREAT_WARNINGS_AS_ERRORS = YES; 399 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 400 | GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; 401 | GCC_WARN_ABOUT_MISSING_NEWLINE = YES; 402 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; 403 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 404 | GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES; 405 | GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES; 406 | GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; 407 | GCC_WARN_MULTIPLE_DEFINITION_TYPES_FOR_SELECTOR = YES; 408 | GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; 409 | GCC_WARN_PEDANTIC = YES; 410 | GCC_WARN_SHADOW = YES; 411 | GCC_WARN_SIGN_COMPARE = YES; 412 | GCC_WARN_STRICT_SELECTOR_MATCH = YES; 413 | GCC_WARN_UNDECLARED_SELECTOR = YES; 414 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 415 | GCC_WARN_UNKNOWN_PRAGMAS = YES; 416 | GCC_WARN_UNUSED_FUNCTION = YES; 417 | GCC_WARN_UNUSED_LABEL = YES; 418 | GCC_WARN_UNUSED_PARAMETER = YES; 419 | GCC_WARN_UNUSED_VARIABLE = YES; 420 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 421 | RUN_CLANG_STATIC_ANALYZER = YES; 422 | SDKROOT = iphoneos; 423 | WARNING_CFLAGS = ( 424 | "-Weverything", 425 | "-Wno-objc-missing-property-synthesis", 426 | ); 427 | }; 428 | name = Release; 429 | }; 430 | /* End XCBuildConfiguration section */ 431 | 432 | /* Begin XCConfigurationList section */ 433 | 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "HRAutoTodoList" */ = { 434 | isa = XCConfigurationList; 435 | buildConfigurations = ( 436 | 1D6058940D05DD3E006BFB54 /* Debug */, 437 | 1D6058950D05DD3E006BFB54 /* Release */, 438 | ); 439 | defaultConfigurationIsVisible = 0; 440 | defaultConfigurationName = Release; 441 | }; 442 | C01FCF4E08A954540054247B /* Build configuration list for PBXProject "HRAutoTodoList" */ = { 443 | isa = XCConfigurationList; 444 | buildConfigurations = ( 445 | C01FCF4F08A954540054247B /* Debug */, 446 | C01FCF5008A954540054247B /* Release */, 447 | ); 448 | defaultConfigurationIsVisible = 0; 449 | defaultConfigurationName = Release; 450 | }; 451 | /* End XCConfigurationList section */ 452 | }; 453 | rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; 454 | } 455 | -------------------------------------------------------------------------------- /Examples/AutoTodoList/HRAutoTodoList.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Examples/AutoTodoList/HRAutoTodoList.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Examples/AutoTodoList/HRAutoTodoList.xcodeproj/xcshareddata/xcschemes/HRAutoTodoList.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 56 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 75 | 77 | 83 | 84 | 85 | 86 | 88 | 89 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /Examples/AutoTodoList/HRAutoTodoList_Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'TodoList1' target in the 'TodoList1' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #import 8 | #endif 9 | -------------------------------------------------------------------------------- /Examples/AutoTodoList/MainWindow.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /Examples/AutoTodoList/TodoList.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | $class 6 | TodoList 7 | items 8 | 9 | 10 | $class 11 | TodoItem 12 | label 13 | Do washing 14 | 15 | 16 | $class 17 | TodoItem 18 | label 19 | Mow lawn 20 | 21 | 22 | $class 23 | TodoItem 24 | label 25 | Write an open source library 26 | 27 | 28 | $class 29 | TodoItem 30 | label 31 | Feed the cat 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /Examples/AutoTodoList/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // TodoList 4 | // 5 | // Created by Nick Lockwood on 08/04/2010. 6 | // Copyright AKQA 2010. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, char *argv[]) 12 | { 13 | @autoreleasepool 14 | { 15 | return UIApplicationMain(argc, argv, nil, nil); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Examples/TodoList/Classes/NewItemViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // NewItemViewController.h 3 | // TodoList 4 | // 5 | // Created by Nick Lockwood on 15/04/2010. 6 | // Copyright 2010 Charcoal Design. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class TodoItem; 12 | 13 | @interface NewItemViewController : UIViewController 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Examples/TodoList/Classes/NewItemViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // NewItemViewController.m 3 | // TodoList 4 | // 5 | // Created by Nick Lockwood on 15/04/2010. 6 | // Copyright 2010 Charcoal Design. All rights reserved. 7 | // 8 | 9 | #import "NewItemViewController.h" 10 | #import "TodoList.h" 11 | #import "TodoItem.h" 12 | 13 | @interface NewItemViewController() 14 | 15 | @property (nonatomic, strong) TodoItem *item; 16 | 17 | @end 18 | 19 | 20 | @implementation NewItemViewController 21 | 22 | #pragma mark - 23 | #pragma mark UITextViewDelegate methods 24 | 25 | - (void)textViewDidChange:(UITextView *)textView 26 | { 27 | if (self.item == nil) 28 | { 29 | //create a new TodoItem and add to list 30 | self.item = [TodoItem itemWithLabel:textView.text]; 31 | [[TodoList sharedList].items addObject:self.item]; 32 | } 33 | else 34 | { 35 | //update the TodoItem 36 | self.item.label = textView.text; 37 | } 38 | 39 | //save the TodoList 40 | [[TodoList sharedList] save]; 41 | } 42 | 43 | #pragma mark - 44 | #pragma mark Cleanup 45 | 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /Examples/TodoList/Classes/NewItemViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /Examples/TodoList/Classes/TodoItem.h: -------------------------------------------------------------------------------- 1 | // 2 | // TodoItem.h 3 | // TodoList 4 | // 5 | // Created by Nick Lockwood on 08/04/2010. 6 | // Copyright 2010 Charcoal Design. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface TodoItem : NSObject 13 | 14 | + (TodoItem *)itemWithLabel:(NSString *)label; 15 | 16 | @property (nonatomic, strong) NSString *label; 17 | @property (nonatomic, assign) BOOL checked; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /Examples/TodoList/Classes/TodoItem.m: -------------------------------------------------------------------------------- 1 | // 2 | // TodoItem.m 3 | // TodoList 4 | // 5 | // Created by Nick Lockwood on 08/04/2010. 6 | // Copyright 2010 Charcoal Design. All rights reserved. 7 | // 8 | 9 | #import "TodoItem.h" 10 | 11 | 12 | @implementation TodoItem 13 | 14 | + (TodoItem *)itemWithLabel:(NSString *)label 15 | { 16 | TodoItem *item = [[self alloc] init]; 17 | item.label = label; 18 | return item; 19 | } 20 | 21 | - (id)initWithCoder:(NSCoder *)decoder 22 | { 23 | if ((self = [super init])) 24 | { 25 | self.label = [decoder decodeObjectForKey:@"label"]; 26 | self.checked = [[decoder decodeObjectForKey:@"checked"] boolValue]; 27 | } 28 | return self; 29 | } 30 | 31 | - (void)encodeWithCoder:(NSCoder *)encoder 32 | { 33 | [encoder encodeObject:self.label forKey:@"label"]; 34 | [encoder encodeObject:@(self.checked) forKey:@"checked"]; 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /Examples/TodoList/Classes/TodoList.h: -------------------------------------------------------------------------------- 1 | // 2 | // TodoList.h 3 | // TodoList 4 | // 5 | // Created by Nick Lockwood on 15/04/2010. 6 | // Copyright 2010 Charcoal Design. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface TodoList : NSObject 13 | 14 | @property (nonatomic, strong) NSMutableArray *items; 15 | 16 | + (TodoList *)sharedList; 17 | - (void)save; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /Examples/TodoList/Classes/TodoList.m: -------------------------------------------------------------------------------- 1 | // 2 | // TodoList.m 3 | // TodoList 4 | // 5 | // Created by Nick Lockwood on 15/04/2010. 6 | // Copyright 2010 Charcoal Design. All rights reserved. 7 | // 8 | 9 | #import "TodoList.h" 10 | #import "TodoItem.h" 11 | #import "HRCoder.h" 12 | 13 | 14 | @implementation TodoList 15 | 16 | #pragma mark - 17 | #pragma mark Loading and saving 18 | 19 | + (NSString *)documentsDirectory 20 | { 21 | return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; 22 | } 23 | 24 | + (TodoList *)sharedList 25 | { 26 | static TodoList *sharedList = nil; 27 | if (sharedList == nil) 28 | { 29 | //attempt to load saved file 30 | NSString *path = [[self documentsDirectory] stringByAppendingPathComponent:@"TodoList.plist"]; 31 | sharedList = [HRCoder unarchiveObjectWithFile:path]; 32 | 33 | //if that fails, load default list from bundle 34 | if (sharedList == nil) 35 | { 36 | path = [[NSBundle mainBundle] pathForResource:@"TodoList" ofType:@"plist"]; 37 | sharedList = [HRCoder unarchiveObjectWithFile:path]; 38 | } 39 | } 40 | return sharedList; 41 | } 42 | 43 | - (void)save; 44 | { 45 | NSString *path = [[[self class] documentsDirectory] stringByAppendingPathComponent:@"TodoList.plist"]; 46 | [HRCoder archiveRootObject:self toFile:path]; 47 | } 48 | 49 | #pragma mark - 50 | #pragma mark NSCoding 51 | 52 | - (id)initWithCoder:(NSCoder *)aDecoder 53 | { 54 | if ((self = [super init])) 55 | { 56 | self.items = [aDecoder decodeObjectForKey:@"items"]; 57 | } 58 | return self; 59 | } 60 | 61 | - (void)encodeWithCoder:(NSCoder *)aCoder 62 | { 63 | [aCoder encodeObject:self.items forKey:@"items"]; 64 | } 65 | 66 | @end 67 | -------------------------------------------------------------------------------- /Examples/TodoList/Classes/TodoListAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // TodoListAppDelegate.h 3 | // TodoList 4 | // 5 | // Created by Nick Lockwood on 08/04/2010. 6 | // Copyright Charcoal Design 2010. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface TodoListAppDelegate : NSObject 12 | 13 | @property (nonatomic, strong) IBOutlet UIWindow *window; 14 | @property (nonatomic, strong) IBOutlet UINavigationController *viewController; 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /Examples/TodoList/Classes/TodoListAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // TodoListAppDelegate.m 3 | // TodoList 4 | // 5 | // Created by Nick Lockwood on 08/04/2010. 6 | // Copyright Charcoal Design 2010. All rights reserved. 7 | // 8 | 9 | #import "TodoListAppDelegate.h" 10 | #import "TodoListViewController.h" 11 | 12 | @implementation TodoListAppDelegate 13 | 14 | @synthesize window; 15 | @synthesize viewController; 16 | 17 | - (void)applicationDidFinishLaunching:(UIApplication *)application 18 | { 19 | // Override point for customization after app launch 20 | [window addSubview:viewController.view]; 21 | [window makeKeyAndVisible]; 22 | } 23 | 24 | 25 | 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /Examples/TodoList/Classes/TodoListViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // TodoList1ViewController.h 3 | // TodoList1 4 | // 5 | // Created by Nick Lockwood on 08/04/2010. 6 | // Copyright Charcoal Design 2010. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface TodoListViewController : UIViewController 12 | 13 | @property (nonatomic, strong) IBOutlet UITableView *tableView; 14 | 15 | - (IBAction)toggleEditing:(id)sender; 16 | - (IBAction)createNewItem; 17 | 18 | @end 19 | 20 | -------------------------------------------------------------------------------- /Examples/TodoList/Classes/TodoListViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // TodoListViewController.m 3 | // TodoList 4 | // 5 | // Created by Nick Lockwood on 08/04/2010. 6 | // Copyright Charcoal Design 2010. All rights reserved. 7 | // 8 | 9 | #import "TodoListViewController.h" 10 | #import "NewItemViewController.h" 11 | #import "TodoItem.h" 12 | #import "TodoList.h" 13 | 14 | 15 | @implementation TodoListViewController 16 | 17 | @synthesize tableView = _tableView; 18 | 19 | - (void)viewDidAppear:(BOOL)animated 20 | { 21 | [super viewDidAppear:animated]; 22 | [self.tableView reloadData]; 23 | } 24 | 25 | - (IBAction)toggleEditing:(id)sender 26 | { 27 | [self.tableView setEditing:!self.tableView.editing animated:YES]; 28 | [sender setTitle:(self.tableView.editing)? @"Done" : @"Edit"]; 29 | } 30 | 31 | - (IBAction)createNewItem 32 | { 33 | UIViewController *viewController = [[NewItemViewController alloc] init]; 34 | [self.navigationController pushViewController:viewController animated:YES]; 35 | } 36 | 37 | #pragma mark - 38 | #pragma mark UITableViewDelegate methods 39 | 40 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 41 | { 42 | TodoItem *item = ([TodoList sharedList].items)[indexPath.row]; 43 | item.checked = !item.checked; 44 | [[TodoList sharedList] save]; 45 | [tableView reloadData]; 46 | } 47 | 48 | - (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath 49 | { 50 | return UITableViewCellEditingStyleDelete; 51 | } 52 | 53 | - (void)tableView:(UITableView *)_tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath 54 | { 55 | [[TodoList sharedList].items removeObjectAtIndex:indexPath.row]; 56 | [[TodoList sharedList] save]; 57 | [self.tableView reloadData]; 58 | } 59 | 60 | #pragma mark - 61 | #pragma mark UITableViewDataSource methods 62 | 63 | - (NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section 64 | { 65 | return [[TodoList sharedList].items count]; 66 | } 67 | 68 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 69 | { 70 | static NSString *cellType = @"Cell"; 71 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellType]; 72 | if (cell == nil) 73 | { 74 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellType]; 75 | } 76 | 77 | TodoItem *item = ([TodoList sharedList].items)[indexPath.row]; 78 | cell.textLabel.text = item.label; 79 | if (item.checked) 80 | { 81 | cell.accessoryType = UITableViewCellAccessoryCheckmark; 82 | } 83 | else 84 | { 85 | cell.accessoryType = UITableViewCellAccessoryNone; 86 | } 87 | 88 | return cell; 89 | } 90 | 91 | #pragma mark - 92 | #pragma mark Cleanup 93 | 94 | - (void)viewDidUnload 95 | { 96 | self.tableView = nil; 97 | [super viewDidUnload]; 98 | } 99 | 100 | 101 | @end 102 | -------------------------------------------------------------------------------- /Examples/TodoList/Classes/TodoListViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /Examples/TodoList/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nicklockwood/HRCoder/758a58f47bc36260b6d8df4c84c962e30f944527/Examples/TodoList/Default-568h@2x.png -------------------------------------------------------------------------------- /Examples/TodoList/HRTodoList-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIconFile 12 | 13 | CFBundleIdentifier 14 | $(PRODUCT_BUNDLE_IDENTIFIER) 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | ${PRODUCT_NAME} 19 | CFBundlePackageType 20 | APPL 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | NSMainNibFile 28 | MainWindow 29 | 30 | 31 | -------------------------------------------------------------------------------- /Examples/TodoList/HRTodoList.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 012EAFC4116E25680023862F /* TodoItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 012EAFC3116E25680023862F /* TodoItem.m */; }; 11 | 01457AEB117723E2005BBF82 /* NewItemViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 01457AE9117723E2005BBF82 /* NewItemViewController.m */; }; 12 | 01457AEC117723E2005BBF82 /* NewItemViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 01457AEA117723E2005BBF82 /* NewItemViewController.xib */; }; 13 | 01457AF2117724D1005BBF82 /* TodoList.m in Sources */ = {isa = PBXBuildFile; fileRef = 01457AF1117724D1005BBF82 /* TodoList.m */; }; 14 | 01CDB22E1611A52300B929AD /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 01CDB22D1611A52300B929AD /* Default-568h@2x.png */; }; 15 | 1D3623260D0F684500981E51 /* TodoListAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D3623250D0F684500981E51 /* TodoListAppDelegate.m */; }; 16 | 1D60589B0D05DD56006BFB54 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; }; 17 | 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; 18 | 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; }; 19 | 288765A50DF7441C002DB57D /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288765A40DF7441C002DB57D /* CoreGraphics.framework */; }; 20 | 28AD733F0D9D9553002E5188 /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 28AD733E0D9D9553002E5188 /* MainWindow.xib */; }; 21 | 28D7ACF80DDB3853001CB0EB /* TodoListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 28D7ACF70DDB3853001CB0EB /* TodoListViewController.m */; }; 22 | B2E4C05B155145E600219D16 /* TodoListViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = B2E4C05A155145E600219D16 /* TodoListViewController.xib */; }; 23 | B2E4C0631551494600219D16 /* HRCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = B2E4C0621551494600219D16 /* HRCoder.m */; }; 24 | B2E4C066155149FF00219D16 /* TodoList.plist in Resources */ = {isa = PBXBuildFile; fileRef = B2E4C065155149FF00219D16 /* TodoList.plist */; }; 25 | /* End PBXBuildFile section */ 26 | 27 | /* Begin PBXFileReference section */ 28 | 012EAFC2116E25680023862F /* TodoItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TodoItem.h; sourceTree = ""; }; 29 | 012EAFC3116E25680023862F /* TodoItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TodoItem.m; sourceTree = ""; }; 30 | 01457AE8117723E2005BBF82 /* NewItemViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NewItemViewController.h; sourceTree = ""; }; 31 | 01457AE9117723E2005BBF82 /* NewItemViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NewItemViewController.m; sourceTree = ""; }; 32 | 01457AEA117723E2005BBF82 /* NewItemViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = NewItemViewController.xib; path = Classes/NewItemViewController.xib; sourceTree = ""; }; 33 | 01457AF0117724D1005BBF82 /* TodoList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TodoList.h; sourceTree = ""; }; 34 | 01457AF1117724D1005BBF82 /* TodoList.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TodoList.m; sourceTree = ""; }; 35 | 01CDB22D1611A52300B929AD /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; 36 | 1D30AB110D05D00D00671497 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 37 | 1D3623240D0F684500981E51 /* TodoListAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TodoListAppDelegate.h; sourceTree = ""; }; 38 | 1D3623250D0F684500981E51 /* TodoListAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TodoListAppDelegate.m; sourceTree = ""; }; 39 | 1D6058910D05DD3D006BFB54 /* HRTodoList.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HRTodoList.app; sourceTree = BUILT_PRODUCTS_DIR; }; 40 | 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 41 | 288765A40DF7441C002DB57D /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 42 | 28AD733E0D9D9553002E5188 /* MainWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MainWindow.xib; sourceTree = ""; }; 43 | 28D7ACF60DDB3853001CB0EB /* TodoListViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TodoListViewController.h; sourceTree = ""; }; 44 | 28D7ACF70DDB3853001CB0EB /* TodoListViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TodoListViewController.m; sourceTree = ""; }; 45 | 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 46 | 32CA4F630368D1EE00C91783 /* HRTodoList_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HRTodoList_Prefix.pch; sourceTree = ""; }; 47 | 8D1107310486CEB800E47090 /* HRTodoList-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "HRTodoList-Info.plist"; plistStructureDefinitionIdentifier = "com.apple.xcode.plist.structure-definition.iphone.info-plist"; sourceTree = ""; }; 48 | B2E4C05A155145E600219D16 /* TodoListViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = TodoListViewController.xib; path = Classes/TodoListViewController.xib; sourceTree = ""; }; 49 | B2E4C0611551494600219D16 /* HRCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HRCoder.h; sourceTree = ""; }; 50 | B2E4C0621551494600219D16 /* HRCoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HRCoder.m; sourceTree = ""; }; 51 | B2E4C065155149FF00219D16 /* TodoList.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = TodoList.plist; sourceTree = ""; }; 52 | /* End PBXFileReference section */ 53 | 54 | /* Begin PBXFrameworksBuildPhase section */ 55 | 1D60588F0D05DD3D006BFB54 /* Frameworks */ = { 56 | isa = PBXFrameworksBuildPhase; 57 | buildActionMask = 2147483647; 58 | files = ( 59 | 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */, 60 | 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */, 61 | 288765A50DF7441C002DB57D /* CoreGraphics.framework in Frameworks */, 62 | ); 63 | runOnlyForDeploymentPostprocessing = 0; 64 | }; 65 | /* End PBXFrameworksBuildPhase section */ 66 | 67 | /* Begin PBXGroup section */ 68 | 01457AF311772690005BBF82 /* View Controllers */ = { 69 | isa = PBXGroup; 70 | children = ( 71 | 1D3623240D0F684500981E51 /* TodoListAppDelegate.h */, 72 | 1D3623250D0F684500981E51 /* TodoListAppDelegate.m */, 73 | 28D7ACF60DDB3853001CB0EB /* TodoListViewController.h */, 74 | 28D7ACF70DDB3853001CB0EB /* TodoListViewController.m */, 75 | 01457AE8117723E2005BBF82 /* NewItemViewController.h */, 76 | 01457AE9117723E2005BBF82 /* NewItemViewController.m */, 77 | ); 78 | name = "View Controllers"; 79 | sourceTree = ""; 80 | }; 81 | 01457AF41177269B005BBF82 /* Model */ = { 82 | isa = PBXGroup; 83 | children = ( 84 | 012EAFC2116E25680023862F /* TodoItem.h */, 85 | 012EAFC3116E25680023862F /* TodoItem.m */, 86 | 01457AF0117724D1005BBF82 /* TodoList.h */, 87 | 01457AF1117724D1005BBF82 /* TodoList.m */, 88 | ); 89 | name = Model; 90 | sourceTree = ""; 91 | }; 92 | 080E96DDFE201D6D7F000001 /* Classes */ = { 93 | isa = PBXGroup; 94 | children = ( 95 | 01457AF311772690005BBF82 /* View Controllers */, 96 | 01457AF41177269B005BBF82 /* Model */, 97 | ); 98 | path = Classes; 99 | sourceTree = ""; 100 | }; 101 | 19C28FACFE9D520D11CA2CBB /* Products */ = { 102 | isa = PBXGroup; 103 | children = ( 104 | 1D6058910D05DD3D006BFB54 /* HRTodoList.app */, 105 | ); 106 | name = Products; 107 | sourceTree = ""; 108 | }; 109 | 29B97314FDCFA39411CA2CEA /* CustomTemplate */ = { 110 | isa = PBXGroup; 111 | children = ( 112 | B2E4C0601551494600219D16 /* HRCoder */, 113 | 080E96DDFE201D6D7F000001 /* Classes */, 114 | 29B97315FDCFA39411CA2CEA /* Other Sources */, 115 | 29B97317FDCFA39411CA2CEA /* Resources */, 116 | 29B97323FDCFA39411CA2CEA /* Frameworks */, 117 | 19C28FACFE9D520D11CA2CBB /* Products */, 118 | ); 119 | name = CustomTemplate; 120 | sourceTree = ""; 121 | }; 122 | 29B97315FDCFA39411CA2CEA /* Other Sources */ = { 123 | isa = PBXGroup; 124 | children = ( 125 | 32CA4F630368D1EE00C91783 /* HRTodoList_Prefix.pch */, 126 | 29B97316FDCFA39411CA2CEA /* main.m */, 127 | ); 128 | name = "Other Sources"; 129 | sourceTree = ""; 130 | }; 131 | 29B97317FDCFA39411CA2CEA /* Resources */ = { 132 | isa = PBXGroup; 133 | children = ( 134 | 01CDB22D1611A52300B929AD /* Default-568h@2x.png */, 135 | B2E4C05A155145E600219D16 /* TodoListViewController.xib */, 136 | 01457AEA117723E2005BBF82 /* NewItemViewController.xib */, 137 | 28AD733E0D9D9553002E5188 /* MainWindow.xib */, 138 | 8D1107310486CEB800E47090 /* HRTodoList-Info.plist */, 139 | B2E4C065155149FF00219D16 /* TodoList.plist */, 140 | ); 141 | name = Resources; 142 | sourceTree = ""; 143 | }; 144 | 29B97323FDCFA39411CA2CEA /* Frameworks */ = { 145 | isa = PBXGroup; 146 | children = ( 147 | 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */, 148 | 1D30AB110D05D00D00671497 /* Foundation.framework */, 149 | 288765A40DF7441C002DB57D /* CoreGraphics.framework */, 150 | ); 151 | name = Frameworks; 152 | sourceTree = ""; 153 | }; 154 | B2E4C0601551494600219D16 /* HRCoder */ = { 155 | isa = PBXGroup; 156 | children = ( 157 | B2E4C0611551494600219D16 /* HRCoder.h */, 158 | B2E4C0621551494600219D16 /* HRCoder.m */, 159 | ); 160 | name = HRCoder; 161 | path = ../../HRCoder; 162 | sourceTree = ""; 163 | }; 164 | /* End PBXGroup section */ 165 | 166 | /* Begin PBXNativeTarget section */ 167 | 1D6058900D05DD3D006BFB54 /* HRTodoList */ = { 168 | isa = PBXNativeTarget; 169 | buildConfigurationList = 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "HRTodoList" */; 170 | buildPhases = ( 171 | 1D60588D0D05DD3D006BFB54 /* Resources */, 172 | 1D60588E0D05DD3D006BFB54 /* Sources */, 173 | 1D60588F0D05DD3D006BFB54 /* Frameworks */, 174 | ); 175 | buildRules = ( 176 | ); 177 | dependencies = ( 178 | ); 179 | name = HRTodoList; 180 | productName = HRTodoList; 181 | productReference = 1D6058910D05DD3D006BFB54 /* HRTodoList.app */; 182 | productType = "com.apple.product-type.application"; 183 | }; 184 | /* End PBXNativeTarget section */ 185 | 186 | /* Begin PBXProject section */ 187 | 29B97313FDCFA39411CA2CEA /* Project object */ = { 188 | isa = PBXProject; 189 | attributes = { 190 | LastUpgradeCheck = 0900; 191 | }; 192 | buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "HRTodoList" */; 193 | compatibilityVersion = "Xcode 3.2"; 194 | developmentRegion = English; 195 | hasScannedForEncodings = 1; 196 | knownRegions = ( 197 | English, 198 | Japanese, 199 | French, 200 | German, 201 | ); 202 | mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */; 203 | projectDirPath = ""; 204 | projectRoot = ""; 205 | targets = ( 206 | 1D6058900D05DD3D006BFB54 /* HRTodoList */, 207 | ); 208 | }; 209 | /* End PBXProject section */ 210 | 211 | /* Begin PBXResourcesBuildPhase section */ 212 | 1D60588D0D05DD3D006BFB54 /* Resources */ = { 213 | isa = PBXResourcesBuildPhase; 214 | buildActionMask = 2147483647; 215 | files = ( 216 | 28AD733F0D9D9553002E5188 /* MainWindow.xib in Resources */, 217 | 01457AEC117723E2005BBF82 /* NewItemViewController.xib in Resources */, 218 | B2E4C05B155145E600219D16 /* TodoListViewController.xib in Resources */, 219 | B2E4C066155149FF00219D16 /* TodoList.plist in Resources */, 220 | 01CDB22E1611A52300B929AD /* Default-568h@2x.png in Resources */, 221 | ); 222 | runOnlyForDeploymentPostprocessing = 0; 223 | }; 224 | /* End PBXResourcesBuildPhase section */ 225 | 226 | /* Begin PBXSourcesBuildPhase section */ 227 | 1D60588E0D05DD3D006BFB54 /* Sources */ = { 228 | isa = PBXSourcesBuildPhase; 229 | buildActionMask = 2147483647; 230 | files = ( 231 | 1D60589B0D05DD56006BFB54 /* main.m in Sources */, 232 | 1D3623260D0F684500981E51 /* TodoListAppDelegate.m in Sources */, 233 | 28D7ACF80DDB3853001CB0EB /* TodoListViewController.m in Sources */, 234 | 012EAFC4116E25680023862F /* TodoItem.m in Sources */, 235 | 01457AEB117723E2005BBF82 /* NewItemViewController.m in Sources */, 236 | 01457AF2117724D1005BBF82 /* TodoList.m in Sources */, 237 | B2E4C0631551494600219D16 /* HRCoder.m in Sources */, 238 | ); 239 | runOnlyForDeploymentPostprocessing = 0; 240 | }; 241 | /* End PBXSourcesBuildPhase section */ 242 | 243 | /* Begin XCBuildConfiguration section */ 244 | 1D6058940D05DD3E006BFB54 /* Debug */ = { 245 | isa = XCBuildConfiguration; 246 | buildSettings = { 247 | ALWAYS_SEARCH_USER_PATHS = NO; 248 | CLANG_ENABLE_OBJC_ARC = YES; 249 | COPY_PHASE_STRIP = NO; 250 | GCC_DYNAMIC_NO_PIC = NO; 251 | GCC_OPTIMIZATION_LEVEL = 0; 252 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 253 | GCC_PREFIX_HEADER = HRTodoList_Prefix.pch; 254 | GCC_TREAT_WARNINGS_AS_ERRORS = YES; 255 | INFOPLIST_FILE = "HRTodoList-Info.plist"; 256 | PRODUCT_BUNDLE_IDENTIFIER = "com.yourcompany.${PRODUCT_NAME:rfc1034identifier}"; 257 | PRODUCT_NAME = HRTodoList; 258 | RUN_CLANG_STATIC_ANALYZER = YES; 259 | SDKROOT = iphoneos; 260 | WARNING_CFLAGS = "-Wall"; 261 | }; 262 | name = Debug; 263 | }; 264 | 1D6058950D05DD3E006BFB54 /* Release */ = { 265 | isa = XCBuildConfiguration; 266 | buildSettings = { 267 | ALWAYS_SEARCH_USER_PATHS = NO; 268 | CLANG_ENABLE_OBJC_ARC = YES; 269 | COPY_PHASE_STRIP = YES; 270 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 271 | GCC_PREFIX_HEADER = HRTodoList_Prefix.pch; 272 | GCC_TREAT_WARNINGS_AS_ERRORS = YES; 273 | INFOPLIST_FILE = "HRTodoList-Info.plist"; 274 | PRODUCT_BUNDLE_IDENTIFIER = "com.yourcompany.${PRODUCT_NAME:rfc1034identifier}"; 275 | PRODUCT_NAME = HRTodoList; 276 | RUN_CLANG_STATIC_ANALYZER = YES; 277 | SDKROOT = iphoneos; 278 | WARNING_CFLAGS = "-Wall"; 279 | }; 280 | name = Release; 281 | }; 282 | C01FCF4F08A954540054247B /* Debug */ = { 283 | isa = XCBuildConfiguration; 284 | buildSettings = { 285 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 286 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 287 | CLANG_WARN_BOOL_CONVERSION = YES; 288 | CLANG_WARN_COMMA = YES; 289 | CLANG_WARN_CONSTANT_CONVERSION = YES; 290 | CLANG_WARN_EMPTY_BODY = YES; 291 | CLANG_WARN_ENUM_CONVERSION = YES; 292 | CLANG_WARN_INFINITE_RECURSION = YES; 293 | CLANG_WARN_INT_CONVERSION = YES; 294 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 295 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 296 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 297 | CLANG_WARN_STRICT_PROTOTYPES = YES; 298 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 299 | CLANG_WARN_UNREACHABLE_CODE = YES; 300 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 301 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 302 | ENABLE_STRICT_OBJC_MSGSEND = YES; 303 | ENABLE_TESTABILITY = YES; 304 | GCC_C_LANGUAGE_STANDARD = c99; 305 | GCC_NO_COMMON_BLOCKS = YES; 306 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 307 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 308 | GCC_WARN_UNDECLARED_SELECTOR = YES; 309 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 310 | GCC_WARN_UNUSED_FUNCTION = YES; 311 | GCC_WARN_UNUSED_VARIABLE = YES; 312 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 313 | ONLY_ACTIVE_ARCH = YES; 314 | SDKROOT = iphoneos; 315 | }; 316 | name = Debug; 317 | }; 318 | C01FCF5008A954540054247B /* Release */ = { 319 | isa = XCBuildConfiguration; 320 | buildSettings = { 321 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 322 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 323 | CLANG_WARN_BOOL_CONVERSION = YES; 324 | CLANG_WARN_COMMA = YES; 325 | CLANG_WARN_CONSTANT_CONVERSION = YES; 326 | CLANG_WARN_EMPTY_BODY = YES; 327 | CLANG_WARN_ENUM_CONVERSION = YES; 328 | CLANG_WARN_INFINITE_RECURSION = YES; 329 | CLANG_WARN_INT_CONVERSION = YES; 330 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 331 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 332 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 333 | CLANG_WARN_STRICT_PROTOTYPES = YES; 334 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 335 | CLANG_WARN_UNREACHABLE_CODE = YES; 336 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 337 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 338 | ENABLE_STRICT_OBJC_MSGSEND = YES; 339 | GCC_C_LANGUAGE_STANDARD = c99; 340 | GCC_NO_COMMON_BLOCKS = YES; 341 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 342 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 343 | GCC_WARN_UNDECLARED_SELECTOR = YES; 344 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 345 | GCC_WARN_UNUSED_FUNCTION = YES; 346 | GCC_WARN_UNUSED_VARIABLE = YES; 347 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 348 | SDKROOT = iphoneos; 349 | }; 350 | name = Release; 351 | }; 352 | /* End XCBuildConfiguration section */ 353 | 354 | /* Begin XCConfigurationList section */ 355 | 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "HRTodoList" */ = { 356 | isa = XCConfigurationList; 357 | buildConfigurations = ( 358 | 1D6058940D05DD3E006BFB54 /* Debug */, 359 | 1D6058950D05DD3E006BFB54 /* Release */, 360 | ); 361 | defaultConfigurationIsVisible = 0; 362 | defaultConfigurationName = Release; 363 | }; 364 | C01FCF4E08A954540054247B /* Build configuration list for PBXProject "HRTodoList" */ = { 365 | isa = XCConfigurationList; 366 | buildConfigurations = ( 367 | C01FCF4F08A954540054247B /* Debug */, 368 | C01FCF5008A954540054247B /* Release */, 369 | ); 370 | defaultConfigurationIsVisible = 0; 371 | defaultConfigurationName = Release; 372 | }; 373 | /* End XCConfigurationList section */ 374 | }; 375 | rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; 376 | } 377 | -------------------------------------------------------------------------------- /Examples/TodoList/HRTodoList.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Examples/TodoList/HRTodoList.xcodeproj/xcshareddata/xcschemes/HRTodoList.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 56 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 75 | 77 | 83 | 84 | 85 | 86 | 88 | 89 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /Examples/TodoList/HRTodoList_Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'TodoList1' target in the 'TodoList1' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #import 8 | #endif 9 | -------------------------------------------------------------------------------- /Examples/TodoList/MainWindow.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /Examples/TodoList/TodoList.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | $class 6 | TodoList 7 | items 8 | 9 | 10 | $class 11 | TodoItem 12 | label 13 | Do washing 14 | 15 | 16 | $class 17 | TodoItem 18 | label 19 | Mow lawn 20 | 21 | 22 | $class 23 | TodoItem 24 | label 25 | Write an open source library 26 | 27 | 28 | $class 29 | TodoItem 30 | label 31 | Feed the cat 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /Examples/TodoList/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // TodoList 4 | // 5 | // Created by Nick Lockwood on 08/04/2010. 6 | // Copyright AKQA 2010. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, char *argv[]) 12 | { 13 | @autoreleasepool { 14 | int retVal = UIApplicationMain(argc, argv, nil, nil); 15 | return retVal; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /HRCoder.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "HRCoder", 3 | "version": "1.3.3", 4 | "summary": "HRCoder is a replacement for the NSKeyedArchiver and NSKeyedUnarchiver classes that read/writes data as human-readable XML.", 5 | "homepage": "https://github.com/nicklockwood/HRCoder", 6 | "license": "zlib", 7 | "authors": "Nick Lockwood", 8 | "source": { 9 | "git": "https://github.com/nicklockwood/HRCoder.git", 10 | "tag": "1.3.3" 11 | }, 12 | "requires_arc": true, 13 | "platforms": { 14 | "ios": "4.3", 15 | "tvos": "9.0", 16 | "osx": "10.6" 17 | }, 18 | "source_files": "HRCoder" 19 | } -------------------------------------------------------------------------------- /HRCoder/HRCoder.h: -------------------------------------------------------------------------------- 1 | // 2 | // HRCoder.h 3 | // 4 | // Version 1.3.3 5 | // 6 | // Created by Nick Lockwood on 24/04/2012. 7 | // Copyright (c) 2011 Charcoal Design 8 | // 9 | // Distributed under the permissive zlib License 10 | // Get the latest version from here: 11 | // 12 | // https://github.com/nicklockwood/HRCoder 13 | // 14 | // This software is provided 'as-is', without any express or implied 15 | // warranty. In no event will the authors be held liable for any damages 16 | // arising from the use of this software. 17 | // 18 | // Permission is granted to anyone to use this software for any purpose, 19 | // including commercial applications, and to alter it and redistribute it 20 | // freely, subject to the following restrictions: 21 | // 22 | // 1. The origin of this software must not be misrepresented; you must not 23 | // claim that you wrote the original software. If you use this software 24 | // in a product, an acknowledgment in the product documentation would be 25 | // appreciated but is not required. 26 | // 27 | // 2. Altered source versions must be plainly marked as such, and must not be 28 | // misrepresented as being the original software. 29 | // 30 | // 3. This notice may not be removed or altered from any source distribution. 31 | // 32 | 33 | 34 | #import 35 | 36 | 37 | #pragma GCC diagnostic push 38 | #pragma GCC diagnostic ignored "-Wobjc-missing-property-synthesis" 39 | 40 | 41 | extern NSString *const HRCoderException; 42 | extern NSString *const HRCoderClassNameKey; 43 | extern NSString *const HRCoderRootObjectKey; 44 | extern NSString *const HRCoderObjectAliasKey; 45 | extern NSString *const HRCoderBase64DataKey; 46 | 47 | 48 | typedef NS_ENUM(NSUInteger, HRCoderFormat) 49 | { 50 | HRCoderFormatXML = 0, 51 | HRCoderFormatJSON, 52 | HRCoderFormatBinary, 53 | }; 54 | 55 | 56 | @interface HRCoder : NSCoder 57 | 58 | @property (nonatomic, assign) HRCoderFormat outputFormat; 59 | 60 | + (id)unarchiveObjectWithPlistOrJSON:(id)plistOrJSON; 61 | + (id)unarchiveObjectWithData:(NSData *)data; 62 | + (id)unarchiveObjectWithFile:(NSString *)path; 63 | + (id)archivedPlistWithRootObject:(id)rootObject; 64 | + (id)archivedJSONWithRootObject:(id)rootObject; 65 | + (NSData *)archivedDataWithRootObject:(id)rootObject; 66 | + (BOOL)archiveRootObject:(id)rootObject toFile:(NSString *)path; 67 | 68 | - (id)initForReadingWithData:(NSData *)data; 69 | - (id)initForWritingWithMutableData:(NSMutableData *)data; 70 | - (void)finishDecoding; 71 | - (void)finishEncoding; 72 | 73 | @end 74 | 75 | 76 | #pragma GCC diagnostic pop 77 | -------------------------------------------------------------------------------- /HRCoder/HRCoder.m: -------------------------------------------------------------------------------- 1 | // 2 | // HRCoder.m 3 | // 4 | // Version 1.3.3 5 | // 6 | // Created by Nick Lockwood on 24/04/2012. 7 | // Copyright (c) 2011 Charcoal Design 8 | // 9 | // Distributed under the permissive zlib License 10 | // Get the latest version from here: 11 | // 12 | // https://github.com/nicklockwood/HRCoder 13 | // 14 | // This software is provided 'as-is', without any express or implied 15 | // warranty. In no event will the authors be held liable for any damages 16 | // arising from the use of this software. 17 | // 18 | // Permission is granted to anyone to use this software for any purpose, 19 | // including commercial applications, and to alter it and redistribute it 20 | // freely, subject to the following restrictions: 21 | // 22 | // 1. The origin of this software must not be misrepresented; you must not 23 | // claim that you wrote the original software. If you use this software 24 | // in a product, an acknowledgment in the product documentation would be 25 | // appreciated but is not required. 26 | // 27 | // 2. Altered source versions must be plainly marked as such, and must not be 28 | // misrepresented as being the original software. 29 | // 30 | // 3. This notice may not be removed or altered from any source distribution. 31 | // 32 | 33 | #import "HRCoder.h" 34 | 35 | 36 | #pragma GCC diagnostic ignored "-Wobjc-missing-property-synthesis" 37 | #pragma GCC diagnostic ignored "-Wdirect-ivar-access" 38 | #pragma GCC diagnostic ignored "-Wselector" 39 | #pragma GCC diagnostic ignored "-Wgnu" 40 | 41 | 42 | #import 43 | #if !__has_feature(objc_arc) 44 | #error This class requires automatic reference counting 45 | #endif 46 | 47 | 48 | NSString *const HRCoderException = @"HRCoderException"; 49 | NSString *const HRCoderClassNameKey = @"$class"; 50 | NSString *const HRCoderRootObjectKey = @"$root"; 51 | NSString *const HRCoderObjectAliasKey = @"$alias"; 52 | NSString *const HRCoderBase64DataKey = @"$data"; 53 | 54 | 55 | @interface HRCoderAliasPlaceholder : NSObject 56 | 57 | + (HRCoderAliasPlaceholder *)placeholder; 58 | 59 | @end 60 | 61 | 62 | @interface NSObject (HRCoding_Private) 63 | 64 | - (id)unarchiveObjectWithHRCoder:(HRCoder *)coder; 65 | - (id)archivedObjectWithHRCoder:(HRCoder *)coder; 66 | 67 | @end 68 | 69 | 70 | @implementation HRCoderAliasPlaceholder 71 | 72 | + (HRCoderAliasPlaceholder *)placeholder 73 | { 74 | static HRCoderAliasPlaceholder *sharedInstance = nil; 75 | if (sharedInstance == nil) 76 | { 77 | sharedInstance = [[self alloc] init]; 78 | } 79 | return sharedInstance; 80 | } 81 | 82 | - (NSString *)description 83 | { 84 | return [NSString stringWithFormat:@"<%@>", [self class]]; 85 | } 86 | 87 | @end 88 | 89 | 90 | @interface HRCoder () 91 | 92 | @property (nonatomic, strong) NSMutableArray *stack; 93 | @property (nonatomic, strong) NSMutableDictionary *knownObjects; 94 | @property (nonatomic, strong) NSMutableDictionary *unresolvedAliases; 95 | @property (nonatomic, strong) NSString *keyPath; 96 | @property (nonatomic, strong) NSMutableData *data; 97 | 98 | @end 99 | 100 | 101 | @implementation HRCoder 102 | 103 | + (NSString *)classNameKey 104 | { 105 | //used by BaseModel 106 | return HRCoderClassNameKey; 107 | } 108 | 109 | - (id)init 110 | { 111 | if ((self = [super init])) 112 | { 113 | self.stack = [NSMutableArray arrayWithObject:[NSMutableDictionary dictionary]]; 114 | _knownObjects = [[NSMutableDictionary alloc] init]; 115 | _unresolvedAliases = [[NSMutableDictionary alloc] init]; 116 | _outputFormat = HRCoderFormatXML; 117 | } 118 | return self; 119 | } 120 | 121 | #pragma mark - 122 | #pragma mark Unarchiving 123 | 124 | + (id)unarchiveObjectWithPlistOrJSON:(__unsafe_unretained id)plistOrJSON 125 | { 126 | return [[[self alloc] init] unarchiveRootObjectWithPlistOrJSON:plistOrJSON]; 127 | } 128 | 129 | + (id)unarchiveObjectWithData:(__unsafe_unretained NSData *)data 130 | { 131 | if (data) 132 | { 133 | //attempt to deserialize as plist 134 | id plistOrJSON = [NSPropertyListSerialization propertyListWithData:data 135 | options:NSPropertyListMutableContainers 136 | format:NULL 137 | error:NULL]; 138 | if (!plistOrJSON) 139 | { 140 | //attempt to deserialize as JSON 141 | plistOrJSON = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:NULL]; 142 | } 143 | 144 | //unarchive 145 | return [self unarchiveObjectWithPlistOrJSON:plistOrJSON]; 146 | } 147 | return nil; 148 | } 149 | 150 | + (id)unarchiveObjectWithFile:(__unsafe_unretained NSString *)path 151 | { 152 | //load the file 153 | return [self unarchiveObjectWithData:[NSData dataWithContentsOfFile:path]]; 154 | } 155 | 156 | - (id)unarchiveRootObjectWithPlistOrJSON:(__unsafe_unretained id)plistOrJSON 157 | { 158 | [_stack removeAllObjects]; 159 | [_knownObjects removeAllObjects]; 160 | [_unresolvedAliases removeAllObjects]; 161 | __autoreleasing id rootObject = [plistOrJSON unarchiveObjectWithHRCoder:self]; 162 | if (rootObject) 163 | { 164 | _knownObjects[HRCoderRootObjectKey] = rootObject; 165 | for (__unsafe_unretained NSString *keyPath in _unresolvedAliases) 166 | { 167 | __autoreleasing id aliasKeyPath = _unresolvedAliases[keyPath]; 168 | __autoreleasing id aliasedObject = _knownObjects[aliasKeyPath]; 169 | __autoreleasing id node = rootObject; 170 | for (__unsafe_unretained NSString *key in [keyPath componentsSeparatedByString:@"."]) 171 | { 172 | __autoreleasing id _node = nil; 173 | if ([node isKindOfClass:[NSArray class]]) 174 | { 175 | NSUInteger index = (NSUInteger)[key integerValue]; 176 | _node = node[index]; 177 | if (_node == [HRCoderAliasPlaceholder placeholder]) 178 | { 179 | node[index] = aliasedObject; 180 | break; 181 | } 182 | } 183 | else 184 | { 185 | _node = [node valueForKey:key]; 186 | if (_node == nil || _node == [HRCoderAliasPlaceholder placeholder]) 187 | { 188 | [node setValue:aliasedObject forKey:key]; 189 | break; 190 | } 191 | } 192 | node = _node; 193 | } 194 | } 195 | } 196 | [self finishDecoding]; 197 | return rootObject; 198 | } 199 | 200 | - (id)initForReadingWithData:(__unsafe_unretained NSData *)data 201 | { 202 | if ((self = [self init])) 203 | { 204 | //attempt to deserialise data as a plist 205 | if (data) 206 | { 207 | //attempt to deserialize as plist 208 | NSPropertyListFormat format; 209 | NSError *error; 210 | __autoreleasing id plistOrJSON = [NSPropertyListSerialization propertyListWithData:data 211 | options:NSPropertyListMutableContainers 212 | format:&format 213 | error:&error]; 214 | if (!plistOrJSON && error) 215 | { 216 | //attempt to deserialize as JSON 217 | plistOrJSON = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error]; 218 | if (!plistOrJSON && error) 219 | { 220 | [NSException raise:HRCoderException format:@"initForReadingWithData: method was unable to parse the supplied data."]; 221 | } 222 | _outputFormat = HRCoderFormatJSON; 223 | } 224 | else 225 | { 226 | //convert to HRCoderFormat 227 | switch (format) 228 | { 229 | case NSPropertyListXMLFormat_v1_0: 230 | case NSPropertyListOpenStepFormat: 231 | { 232 | _outputFormat = HRCoderFormatXML; 233 | break; 234 | } 235 | case NSPropertyListBinaryFormat_v1_0: 236 | { 237 | _outputFormat = HRCoderFormatBinary; 238 | break; 239 | } 240 | } 241 | } 242 | 243 | //only works if root object is a dictionary 244 | if ([plistOrJSON isKindOfClass:[NSDictionary class]]) 245 | { 246 | [_stack addObject:plistOrJSON]; 247 | } 248 | else 249 | { 250 | [NSException raise:HRCoderException format:@"initForReadingWithData: method requires that the root object in the plist data is an NSDictionary. Decoding an %@ is not supported with this method. Try using unarchiveObjectWithData: instead.", [plistOrJSON class]]; 251 | } 252 | } 253 | } 254 | return self; 255 | } 256 | 257 | - (void)finishDecoding 258 | { 259 | [_unresolvedAliases removeAllObjects]; 260 | [_knownObjects removeAllObjects]; 261 | [_stack setArray:[NSMutableArray arrayWithObject:[NSMutableDictionary dictionary]]]; 262 | } 263 | 264 | 265 | #pragma mark - 266 | #pragma mark Archiving 267 | 268 | + (id)archivedPlistWithRootObject:(__unsafe_unretained id)rootObject 269 | { 270 | HRCoder *coder = [[self alloc] init]; 271 | return [coder archiveRootObject:rootObject]; 272 | } 273 | 274 | + (id)archivedJSONWithRootObject:(__unsafe_unretained id)rootObject 275 | { 276 | HRCoder *coder = [[self alloc] init]; 277 | coder.outputFormat = HRCoderFormatJSON; 278 | return [coder archiveRootObject:rootObject]; 279 | } 280 | 281 | + (NSData *)archivedDataWithRootObject:(__unsafe_unretained id)rootObject 282 | { 283 | __autoreleasing NSMutableData *data = [NSMutableData data]; 284 | __autoreleasing HRCoder *coder = [[self alloc] initForWritingWithMutableData:data]; 285 | [coder archiveRootObject:rootObject]; 286 | return data; 287 | } 288 | 289 | + (BOOL)archiveRootObject:(__unsafe_unretained id)rootObject toFile:(__unsafe_unretained NSString *)path 290 | { 291 | return [[self archivedDataWithRootObject:rootObject] writeToFile:path atomically:YES]; 292 | } 293 | 294 | - (id)initForWritingWithMutableData:(__unsafe_unretained NSMutableData *)data 295 | { 296 | if ((self = [self init])) 297 | { 298 | //set data 299 | self.data = data; 300 | } 301 | return self; 302 | } 303 | 304 | - (id)archiveRootObject:(__unsafe_unretained id)rootObject 305 | { 306 | [_knownObjects removeAllObjects]; 307 | [self encodeRootObject:rootObject]; 308 | __autoreleasing id plistOrJSON = [_stack lastObject]; 309 | [self finishEncoding]; 310 | return plistOrJSON; 311 | } 312 | 313 | - (void)finishEncoding 314 | { 315 | if (_data && _stack.count) 316 | { 317 | id object = (__nonnull id)[_stack lastObject]; 318 | switch (_outputFormat) 319 | { 320 | case HRCoderFormatXML: 321 | case HRCoderFormatBinary: 322 | { 323 | NSData *data = (NSData *__nonnull)[NSPropertyListSerialization dataWithPropertyList:object 324 | format:(_outputFormat == HRCoderFormatXML)? NSPropertyListXMLFormat_v1_0: NSPropertyListBinaryFormat_v1_0 325 | options:0 326 | error:NULL]; 327 | [_data setData:data]; 328 | break; 329 | } 330 | case HRCoderFormatJSON: 331 | { 332 | NSData *data = (NSData *__nonnull)[NSJSONSerialization dataWithJSONObject:object options:(NSJSONWritingOptions)0 error:NULL]; 333 | [_data setData:data]; 334 | break; 335 | } 336 | } 337 | self.data = nil; 338 | } 339 | [_knownObjects removeAllObjects]; 340 | [_stack setArray:[NSMutableArray arrayWithObject:[NSMutableDictionary dictionary]]]; 341 | } 342 | 343 | 344 | #pragma mark - 345 | #pragma mark NSCoding 346 | 347 | - (BOOL)allowsKeyedCoding 348 | { 349 | return YES; 350 | } 351 | 352 | - (BOOL)containsValueForKey:(__unsafe_unretained NSString *)key 353 | { 354 | return [_stack lastObject][key] != nil; 355 | } 356 | 357 | - (id)encodedObject:(__unsafe_unretained id)object forKey:(__unsafe_unretained NSString *)key 358 | { 359 | if (object && key) 360 | { 361 | Class coderClass = [object classForCoder]; 362 | if (![@[[NSString class], [NSNumber class], [NSValue class], [NSDate class], [NSNull class]] containsObject:coderClass]) 363 | { 364 | for (__unsafe_unretained NSString *aliasKeyPath in _knownObjects) 365 | { 366 | if (_knownObjects[aliasKeyPath] == object) 367 | { 368 | //create alias 369 | return @{HRCoderObjectAliasKey: aliasKeyPath}; 370 | } 371 | } 372 | } 373 | 374 | //encode object 375 | __autoreleasing NSString *oldKeyPath = _keyPath; 376 | self.keyPath = _keyPath? [_keyPath stringByAppendingPathExtension:key]: key; 377 | _knownObjects[_keyPath] = object; 378 | __autoreleasing id encodedObject = [object archivedObjectWithHRCoder:self]; 379 | self.keyPath = oldKeyPath; 380 | return encodedObject; 381 | } 382 | return nil; 383 | } 384 | 385 | - (void)encodeObject:(__unsafe_unretained id)objv forKey:(__unsafe_unretained NSString *)key 386 | { 387 | __autoreleasing id object = [self encodedObject:objv forKey:key]; 388 | if (object) [_stack lastObject][key] = object; 389 | } 390 | 391 | - (void)encodeRootObject:(__unsafe_unretained id)rootObject 392 | { 393 | if (rootObject) 394 | { 395 | _knownObjects[HRCoderRootObjectKey] = rootObject; 396 | [_stack setArray:[NSMutableArray arrayWithObject:[rootObject archivedObjectWithHRCoder:self]]]; 397 | } 398 | } 399 | 400 | - (void)encodeConditionalObject:(id)objv forKey:(__unsafe_unretained NSString *)key 401 | { 402 | for (__unsafe_unretained id object in [_knownObjects allValues]) 403 | { 404 | if (object == objv) 405 | { 406 | [self encodeObject:objv forKey:key]; 407 | break; 408 | } 409 | } 410 | } 411 | 412 | - (void)encodeBool:(BOOL)boolv forKey:(__unsafe_unretained NSString *)key 413 | { 414 | [_stack lastObject][key] = @(boolv); 415 | } 416 | 417 | - (void)encodeInt:(int)intv forKey:(__unsafe_unretained NSString *)key 418 | { 419 | [_stack lastObject][key] = @(intv); 420 | } 421 | 422 | - (void)encodeInt32:(int32_t)intv forKey:(__unsafe_unretained NSString *)key 423 | { 424 | [_stack lastObject][key] = @(intv); 425 | } 426 | 427 | - (void)encodeInt64:(int64_t)intv forKey:(__unsafe_unretained NSString *)key 428 | { 429 | [_stack lastObject][key] = @(intv); 430 | } 431 | 432 | - (void)encodeFloat:(float)realv forKey:(__unsafe_unretained NSString *)key 433 | { 434 | [_stack lastObject][key] = @(realv); 435 | } 436 | 437 | - (void)encodeDouble:(double)realv forKey:(__unsafe_unretained NSString *)key 438 | { 439 | [_stack lastObject][key] = @(realv); 440 | } 441 | 442 | - (void)encodeBytes:(const uint8_t *)bytesp length:(NSUInteger)lenv forKey:(__unsafe_unretained NSString *)key 443 | { 444 | [_stack lastObject][key] = [[NSData dataWithBytes:bytesp length:lenv] archivedObjectWithHRCoder:self]; 445 | } 446 | 447 | - (id)decodeObject:(id)object forKey:(__unsafe_unretained NSString *)key 448 | { 449 | if (object && key) 450 | { 451 | //new keypath 452 | __autoreleasing NSString *newKeyPath = _keyPath? [_keyPath stringByAppendingPathExtension:key]: key; 453 | 454 | //check if object is an alias (TODO: move this into NSictionary.unarchiveObjectWithDecoder:) 455 | if ([object isKindOfClass:[NSDictionary class]]) 456 | { 457 | NSDictionary *dictionary = object; 458 | __autoreleasing NSString *aliasKeyPath = dictionary[HRCoderObjectAliasKey]; 459 | if (aliasKeyPath) 460 | { 461 | //object alias 462 | __autoreleasing id decodedObject = _knownObjects[aliasKeyPath]; 463 | if (!decodedObject) 464 | { 465 | _unresolvedAliases[newKeyPath] = aliasKeyPath; 466 | decodedObject = [HRCoderAliasPlaceholder placeholder]; 467 | } 468 | return decodedObject; 469 | } 470 | } 471 | 472 | //new object 473 | __autoreleasing NSString *oldKeyPath = _keyPath; 474 | self.keyPath = newKeyPath; 475 | __autoreleasing id decodedObject = [object unarchiveObjectWithHRCoder:self]; 476 | if (decodedObject) _knownObjects[_keyPath] = decodedObject; 477 | self.keyPath = oldKeyPath; 478 | return decodedObject; 479 | } 480 | return nil; 481 | } 482 | 483 | - (id)decodeObjectForKey:(__unsafe_unretained NSString *)key 484 | { 485 | return [self decodeObject:[_stack lastObject][key] forKey:key]; 486 | } 487 | 488 | - (BOOL)decodeBoolForKey:(__unsafe_unretained NSString *)key 489 | { 490 | return [[_stack lastObject][key] boolValue]; 491 | } 492 | 493 | - (int)decodeIntForKey:(__unsafe_unretained NSString *)key 494 | { 495 | return [[_stack lastObject][key] intValue]; 496 | } 497 | 498 | - (int32_t)decodeInt32ForKey:(__unsafe_unretained NSString *)key 499 | { 500 | return (int32_t)[[_stack lastObject][key] longValue]; 501 | } 502 | 503 | - (int64_t)decodeInt64ForKey:(__unsafe_unretained NSString *)key 504 | { 505 | return [[_stack lastObject][key] longLongValue]; 506 | } 507 | 508 | - (float)decodeFloatForKey:(__unsafe_unretained NSString *)key 509 | { 510 | return [[_stack lastObject][key] floatValue]; 511 | } 512 | 513 | - (double)decodeDoubleForKey:(__unsafe_unretained NSString *)key 514 | { 515 | return [[_stack lastObject][key] doubleValue]; 516 | } 517 | 518 | - (const uint8_t *)decodeBytesForKey:(__unsafe_unretained NSString *)key returnedLength:(NSUInteger *)lengthp 519 | { 520 | __autoreleasing NSData *data = [[_stack lastObject][key] unarchiveObjectWithHRCoder:self]; 521 | *lengthp = [data length]; 522 | return data.bytes; 523 | } 524 | 525 | @end 526 | 527 | 528 | @implementation NSObject(HRCoding) 529 | 530 | - (id)unarchiveObjectWithHRCoder:(__unused HRCoder *)coder 531 | { 532 | return self; 533 | } 534 | 535 | - (id)archivedObjectWithHRCoder:(__unsafe_unretained HRCoder *)coder 536 | { 537 | __autoreleasing NSMutableDictionary *result = [NSMutableDictionary dictionary]; 538 | [coder.stack addObject:result]; 539 | result[HRCoderClassNameKey] = NSStringFromClass([self classForCoder]); 540 | [(id )[self replacementObjectForCoder:coder] encodeWithCoder:coder]; 541 | [coder.stack removeLastObject]; 542 | return result; 543 | } 544 | 545 | @end 546 | 547 | 548 | @implementation NSDictionary(HRCoding) 549 | 550 | - (id)unarchiveObjectWithHRCoder:(__unsafe_unretained HRCoder *)coder 551 | { 552 | __autoreleasing NSString *className = self[HRCoderClassNameKey]; 553 | __autoreleasing NSString *base64Data = self[HRCoderBase64DataKey]; 554 | if (base64Data) 555 | { 556 | //data 557 | Class dataClass = NSClassFromString(className ?: @"NSData"); 558 | 559 | #if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_9) || \ 560 | (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0) 561 | 562 | if (![NSData instancesRespondToSelector:@selector(initWithBase64EncodedString:options:)]) 563 | { 564 | return [[dataClass alloc] initWithBase64Encoding:base64Data]; 565 | } 566 | else 567 | #endif 568 | { 569 | return [[dataClass alloc] initWithBase64EncodedString:base64Data options:(NSDataBase64DecodingOptions)0]; 570 | } 571 | } 572 | else if (className) 573 | { 574 | //encoded object 575 | [coder.stack addObject:self]; 576 | Class objectClass = NSClassFromString(className); 577 | __autoreleasing id object = [[[objectClass alloc] initWithCoder:coder] awakeAfterUsingCoder:coder]; 578 | [coder.stack removeLastObject]; 579 | return object; 580 | } 581 | else 582 | { 583 | //ordinary dictionary 584 | __autoreleasing NSMutableDictionary *result = [NSMutableDictionary dictionary]; 585 | [coder.stack addObject:self]; 586 | for (__unsafe_unretained NSString *key in self) 587 | { 588 | __autoreleasing id object = [coder decodeObjectForKey:key]; 589 | if (object) result[key] = object; 590 | } 591 | [coder.stack removeLastObject]; 592 | return result; 593 | } 594 | } 595 | 596 | - (id)archivedObjectWithHRCoder:(__unsafe_unretained HRCoder *)coder 597 | { 598 | __autoreleasing NSMutableDictionary *result = [NSMutableDictionary dictionary]; 599 | [coder.stack addObject:result]; 600 | [self enumerateKeysAndObjectsUsingBlock:^(__unsafe_unretained id key, __unsafe_unretained id obj, __unused BOOL *stop) { 601 | [coder encodeObject:obj forKey:key]; 602 | }]; 603 | [coder.stack removeLastObject]; 604 | return result; 605 | } 606 | 607 | @end 608 | 609 | 610 | @implementation NSArray(HRCoding) 611 | 612 | - (id)unarchiveObjectWithHRCoder:(__unsafe_unretained HRCoder *)coder 613 | { 614 | __autoreleasing NSMutableArray *result = [NSMutableArray array]; 615 | for (NSUInteger i = 0; i < [self count]; i++) 616 | { 617 | NSString *key = [@(i) description]; 618 | id encodedObject = self[i]; 619 | id decodedObject = [coder decodeObject:encodedObject forKey:key]; 620 | [result addObject:decodedObject]; 621 | } 622 | return result; 623 | } 624 | 625 | - (id)archivedObjectWithHRCoder:(__unsafe_unretained HRCoder *)coder 626 | { 627 | NSMutableArray *result = [NSMutableArray array]; 628 | for (NSUInteger i = 0; i < [self count]; i++) 629 | { 630 | id object = self[i]; 631 | NSString *key = [@(i) description]; 632 | [result addObject:[coder encodedObject:object forKey:key]]; 633 | } 634 | return result; 635 | } 636 | 637 | @end 638 | 639 | 640 | @implementation NSString(HRCoding) 641 | 642 | - (id)unarchiveObjectWithHRCoder:(__unused HRCoder *)coder 643 | { 644 | return self; 645 | } 646 | 647 | - (id)archivedObjectWithHRCoder:(__unsafe_unretained HRCoder *)coder 648 | { 649 | if ([self classForCoder] == [NSMutableString class]) 650 | { 651 | return [super archivedObjectWithHRCoder:coder]; 652 | } 653 | return self; 654 | } 655 | 656 | @end 657 | 658 | 659 | @implementation NSNumber(HRCoding) 660 | 661 | - (id)unarchiveObjectWithHRCoder:(__unused HRCoder *)coder 662 | { 663 | return self; 664 | } 665 | 666 | - (id)archivedObjectWithHRCoder:(__unused HRCoder *)coder 667 | { 668 | return self; 669 | } 670 | 671 | @end 672 | 673 | 674 | @implementation NSData(HRCoding) 675 | 676 | - (id)unarchiveObjectWithHRCoder:(__unused HRCoder *)coder 677 | { 678 | return self; 679 | } 680 | 681 | - (id)archivedObjectWithHRCoder:(__unsafe_unretained HRCoder *)coder 682 | { 683 | Class coderClass = [self classForCoder]; 684 | if (coder.outputFormat == HRCoderFormatJSON) 685 | { 686 | NSString *base64String = nil; 687 | 688 | #if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_9) || \ 689 | (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_7_0) 690 | 691 | if (![self respondsToSelector:@selector(base64EncodedStringWithOptions:)]) 692 | { 693 | base64String = [self base64Encoding]; 694 | } 695 | else 696 | #endif 697 | { 698 | base64String = [self base64EncodedStringWithOptions:(NSDataBase64EncodingOptions)0]; 699 | } 700 | return @{HRCoderClassNameKey: NSStringFromClass(coderClass), HRCoderBase64DataKey: base64String}; 701 | } 702 | else if ([self classForCoder] == [NSMutableData class]) 703 | { 704 | return [super archivedObjectWithHRCoder:coder]; 705 | } 706 | return self; 707 | } 708 | 709 | @end 710 | 711 | 712 | @implementation NSDate(HRCoding) 713 | 714 | - (id)unarchiveObjectWithHRCoder:(__unused HRCoder *)coder 715 | { 716 | return self; 717 | } 718 | 719 | - (id)archivedObjectWithHRCoder:(__unsafe_unretained HRCoder *)coder 720 | { 721 | if (coder.outputFormat == HRCoderFormatJSON) 722 | { 723 | return [super archivedObjectWithHRCoder:coder]; 724 | } 725 | return self; 726 | } 727 | 728 | @end 729 | 730 | 731 | @implementation NSNull(HRCoding) 732 | 733 | - (id)unarchiveObjectWithHRCoder:(__unused HRCoder *)coder 734 | { 735 | return self; 736 | } 737 | 738 | - (id)archivedObjectWithHRCoder:(__unsafe_unretained HRCoder *)coder 739 | { 740 | if (coder.outputFormat != HRCoderFormatJSON) 741 | { 742 | return [super archivedObjectWithHRCoder:coder]; 743 | } 744 | return self; 745 | } 746 | 747 | @end 748 | -------------------------------------------------------------------------------- /LICENCE.md: -------------------------------------------------------------------------------- 1 | HRCoder 2 | 3 | Copyright (C) 2012 Charcoal Design 4 | 5 | This software is provided 'as-is', without any express or implied 6 | warranty. In no event will the authors be held liable for any damages 7 | arising from the use of this software. 8 | 9 | Permission is granted to anyone to use this software for any purpose, 10 | including commercial applications, and to alter it and redistribute it 11 | freely, subject to the following restrictions: 12 | 13 | 1. The origin of this software must not be misrepresented; you must not 14 | claim that you wrote the original software. If you use this software 15 | in a product, an acknowledgment in the product documentation would be 16 | appreciated but is not required. 17 | 18 | 2. Altered source versions must be plainly marked as such, and must not be 19 | misrepresented as being the original software. 20 | 21 | 3. This notice may not be removed or altered from any source distribution. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/nicklockwood/HRCoder.svg)](https://travis-ci.org/nicklockwood/HRCoder) 2 | 3 | 4 | Purpose 5 | -------------- 6 | 7 | HRCoder is a replacement for the NSKeyedArchiver and NSKeyedUnarchiver classes. Although the NSKeyedArchiver writes data in the standard Plist format, the structure of the Plist makes it hard to read, and nearly impossible to generate by hand. 8 | 9 | The *HR* stands for *Human Readable*. HRCoder saves files in a simpler format than NSKeyedArchiver; Standard objects such as strings, dictionaries, arrays, numbers, booleans and binary data are all saved and loaded using the standard Plist primitives, and any other type of object is saved as a simple dictionary, with the addition of a $class key to indicate the object type. 10 | 11 | This makes it possible to easily generate HRCoder-compatible Plist files by hand, and then load them using the standard NSCoding protocol. You can also read and manually edit files saved by the HRCoder class without fear of corrupting the file. 12 | 13 | The simple dictionary/array-based format used by HRCoding can also be easily stored as JSON, opening up more options for serialisation (NSKeyedArchiver is tied to Plists and cannot easily be used to save as JSON without creating a Plist as an intermediate step). 14 | 15 | HRCoder is designed to work with the AutoCoding library (https://github.com/nicklockwood/AutoCoding), which can automatically write the `initWithCoder:` and `encodeWithCoder:` methods for your classes. Check out the *AutoTodoList* example to see how this works. 16 | 17 | HRCoder is also designed to work hand-in-hand with the BaseModel library (https://github.com/nicklockwood/BaseModel) which forms the basis for building a powerful model hierarchy for your project with minimal effort. Check the *HRTodoList* example included in the BaseModel repository for an example of how these libraries can work together. 18 | 19 | 20 | Supported OS & SDK Versions 21 | ----------------------------- 22 | 23 | * Supported build target - iOS 11.0 / Mac OS 10.12 (Xcode 9.0) 24 | * Earliest supported deployment target - iOS 9.0 / Mac OS 10.10 25 | * Earliest compatible deployment target - iOS 4.0 / Mac OS 10.6 26 | 27 | NOTE: 'Supported' means that the library has been tested with this version. 'Compatible' means that the library should work on this OS version (i.e. it doesn't rely on any unavailable SDK features) but is no longer being tested for compatibility and may require tweaking or bug fixes to run correctly. 28 | 29 | 30 | ARC Compatibility 31 | ------------------ 32 | 33 | As of version 1.3, HRCoder requires ARC. If you wish to use HRCoder in a non-ARC project, just add the -fobjc-arc compiler flag to the HRCoder.m class file. To do this, go to the Build Phases tab in your target settings, open the Compile Sources group, double-click HRCoder.m in the list and type -fobjc-arc into the popover. 34 | 35 | If you wish to convert your whole project to ARC, comment out the #error line in HRCoder.m, then run the Edit > Refactor > Convert to Objective-C ARC... tool in Xcode and make sure all files that you wish to use ARC for (including HRCoder.m) are checked. 36 | 37 | 38 | Thread Safety 39 | -------------- 40 | 41 | It is not safe to access a single HRCoder instance from multiple threads concurrently, hower using the HRCoder class methods to encode and decode objects is completely thread-safe. 42 | 43 | 44 | Installation 45 | -------------- 46 | 47 | To use HRCoder, just drag the HRCoder.h and .m files into your project. 48 | 49 | 50 | HRCoder properties 51 | ------------------------- 52 | 53 | @property (nonatomic, assign) HRCoderFormat outputFormat; 54 | 55 | This property can be used to set the output format when serialising HRCoded objects. Possible values are `HRCoderFormatXML`, `HRCoderFormatJSON` and `HRCoderFormatBinary`. The default value is `HRCoderFormatXML`, which produces an XML Plist. 56 | 57 | 58 | HRCoder methods 59 | ----------------------------- 60 | 61 | HRCoder implements the following methods, which mirror those of the NSKeyedArchiver and NSKeyedUnarchiver classes. 62 | 63 | + (id)unarchiveObjectWithPlistOrJSON:(id)plistOrJSON; 64 | 65 | Constructs an object tree from an encoded Plist or JSON object and returns it. The plistOrJSON parameter can be any object that is natively supported by the Plist or JSON formats. This would typically be a container object such as an NSDictionary or NSArray. If any other kind of object is supplied it will be returned without modification. 66 | 67 | Note that this object need not actually be loaded from a Plist or JSON file you can create such an object programmatically. 68 | 69 | + (id)unarchiveObjectWithData:(NSData *)data; 70 | 71 | Loads a serialised plist from an NSData object and returns an unarchived object tree by calling `unarchiveObjectWithPlist:` on the root object in the file. Supports text, JSON, XML or binary-formatted data. Data is deserialised using mutable containers to ensure that mutability of encoded arrays and dictionaries is preserved. If you'd prefer immutable objects, load the object yourself directly using the `NSPropertyListSerialization` or `NSJSONSerialization` classes. 72 | 73 | + (id)unarchiveObjectWithFile:(NSString *)path; 74 | 75 | Loads a data file in Plist format and returns an unarchived object tree by calling `unarchiveObjectWithData:`. 76 | 77 | + (id)archivedPlistWithRootObject:(id)object; 78 | 79 | Encodes the passed object as a hierarchy of Plist-compatible objects, and returns it. The resultant object will typically be one of NSDictionary, NSArray, NSString, NSData, NSDate or NSNumber. This object is then safe to pass to NSPropertyListSerialisation for conversion to raw data or saving to a file. 80 | 81 | + (id)archivedJSONWithRootObject:(id)object; 82 | 83 | Encodes the passed object as a hierarchy of JSON-compatible objects, and returns it. The resultant object will typically be one of NSDictionary, NSArray, NSString, NSNumber or NSNull. This object is then safe to pass to NSPropertyListSerialisation for conversion to raw data or saving to a file. 84 | 85 | + (NSData *)archivedDataWithRootObject:(id)rootObject; 86 | 87 | Encodes the passed object by calling `archivedPlistWithRootObject:` and then serialises it to data using the XML property list format. 88 | 89 | + (BOOL)archiveRootObject:(id)rootObject toFile:(NSString *)path; 90 | 91 | Encodes the passed object by calling `archivedDataWithRootObject:` and then saves it to the file path specified. The file is saved atomically to prevent data corruption. 92 | 93 | - (id)initForReadingWithData:(NSData *)data; 94 | 95 | This method is used for creating an HRCoder instance from an encoded NSData object that can be passed directly to the initWithCoder: method of a class. It is included mostly for compatibility with the `NSKeyedUnarchiver` class, which has the same method. The data must contain a plist-encoded NSDictionary object. Other root objects types such as NSArray are not supported with this method (you can use the `unarchiveObjectWithData:` method to load data containing other root object types). 96 | 97 | - (id)initForWritingWithMutableData:(NSMutableData *)data; 98 | 99 | This method is used to create an HTCoder object for the purpose of writing to a data object. Once you have created the HRCoder instance, you can pass it to the `encodeWithCoder:` method of an object to encode it. Once you have written an object, calling `finishEncoding` will write the serialised plist data into the NSMutableData object. 100 | 101 | - (void)finishDecoding; 102 | 103 | Finishes decoding data that was opened using the `initForReadingWithData: method.` 104 | 105 | - (void)finishEncoding; 106 | 107 | When a file has been opened using the `initForWritingWithMutableData:` method, this will close it off and write the serialised data to the originally specified NSMutableData object. 108 | 109 | 110 | Plist structure 111 | --------------------------- 112 | 113 | Any ordinary Plist can be loaded using HECoder and it will behave the same way as if you loaded it using `NSPropertyListSerialization`. To add custom classes to the Plist, define the object as if it was a dictionary, but add an additional `$class` key with the class name of the object. For example, this code will result in an ordinary NSDictionary: 114 | 115 | 116 | coming 117 | Hello 118 | going 119 | Goodbye 120 | 121 | 122 | But this will load an object of class `Greetings` (assuming that class exists in your project). 123 | 124 | 125 | $class 126 | Greetings 127 | coming 128 | Hello 129 | going 130 | Goodbye 131 | 132 | 133 | Another feature of NSCoding that isn't supported by ordinary Plists is circular references. HRCoding supports this using the an aliasing mechanism. If you want to re-use an object in another place within your object hierarchy, you can do this using the following syntax: 134 | 135 | 136 | $alias 137 | path.to.the.object 138 | 139 | 140 | The alias value is a key path to the original object within the hierarchy. To see this in context, here is a simple example of how this would work: 141 | 142 | 143 | object1 144 | Hello World 145 | object2 146 | 147 | $alias 148 | object1 149 | 150 | 151 | 152 | Once loaded, the object1 and object2 properties will both point at the same "Hello World" string instance (not just the same value, but the same actual object). This also works with arrays - just use the array index as the alias key: 153 | 154 | 155 | Hello World 156 | 157 | $alias 158 | 0 159 | 160 | 161 | 162 | Forward references are permitted in aliases (i.e. aliasing an object which is declared later in the hierarchy), however this should be avoided as possible as it involves inserting `HRCoderAliasPlaceholder` objects as the object tree is deserialised, and then replacing these later, which incurs a slight performance penalty. 163 | 164 | Note that if you are using aliases you should be careful not to call methods on deserialised objects insider your `initWithCoder:` method, as they may not always be of the expected type until loading is complete. 165 | 166 | 167 | Release notes 168 | --------------- 169 | 170 | Version 1.3.3 171 | 172 | - Fixed warnings in Xcode 9 173 | 174 | Version 1.3.2 175 | 176 | - Fixed crash when encoding binary data in JSON files (affected mutable strings) 177 | - Fixed some additional warnings in Xcode 6 178 | 179 | Version 1.3.1 180 | 181 | - Fixed bug with encoding conditional objects 182 | - HRCoder can now encode NSData objects as JSON using base 64 encoding 183 | 184 | Version 1.3 185 | 186 | - outputFormat enum is now of type HRCoderFormat, and includes JSON as an option 187 | - When using the JSON output format, NSData and NSDate objects are now encoded in a JSON-compatible format 188 | - HRCoder can now load data encoded in JSON format 189 | - Now complies with -Weverything warning level 190 | - Improved performance when using ARC 191 | - HRCoder now requires ARC 192 | 193 | Version 1.2.3 194 | 195 | - Fixed a bug where objects that override isEqual would be incorrectly aliased 196 | - Objects of type NSNumber, NSDate and short NSStrings will no longer be aliased 197 | - Now complies with -Wall and -Wextra warning levels 198 | 199 | Version 1.2.2 200 | 201 | - Fixed a bug where objects could be skipped when decoding, depending on the order of items in the plist 202 | - Added CocoaPods podspec 203 | 204 | Version 1.2.1 205 | 206 | - Fixed bug where nested NSDictionaries were not decoded correctly 207 | 208 | Version 1.2 209 | 210 | - Added `initForReadingWithData:` and `initForWritingWithMutableData:` methods, which improve compatibility with the NSKeyedArchiver/Unarchiver class interfaces. 211 | - Added outputFormat property for setting the Plist format when saving 212 | 213 | Version 1.1.3 214 | 215 | - Fixed analyzer warning due to over-autorelease of decoded object 216 | 217 | Version 1.1.2 218 | 219 | - Fixed crash when attempting to archive a nil object property 220 | 221 | Version 1.1.1 222 | 223 | - HRCoder now calls the `awakeAfterUsingCoder:` method on objects after they are unarchived. 224 | - HRCoder now calls the `classForCoder` and `replacementObjectForCoder:` methods on an object prior to archiving. 225 | 226 | Version 1.1 227 | 228 | - Added `unarchiveObjectWithData:` and `archivedDataWithRootObject:` methods 229 | - HRCoder now saves in XML format instead of binary by default 230 | - Now supports 32-bit CPUs on Mac OS 10.6 231 | 232 | Version 1.0 233 | 234 | - Initial release -------------------------------------------------------------------------------- /Tests/UnitTests.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 01882F1C19BFCD21006994D0 /* HRCoderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 01882F1B19BFCD21006994D0 /* HRCoderTests.m */; }; 11 | 01882F2019BFCD29006994D0 /* HRCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 01882F1F19BFCD29006994D0 /* HRCoder.m */; }; 12 | 01D28C891907BFC80021C719 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 01D28C881907BFC80021C719 /* XCTest.framework */; }; 13 | 01D28C8A1907BFC80021C719 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 01D28C6F1907BFC80021C719 /* Foundation.framework */; }; 14 | 01D28C8B1907BFC80021C719 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 01D28C731907BFC80021C719 /* UIKit.framework */; }; 15 | /* End PBXBuildFile section */ 16 | 17 | /* Begin PBXFileReference section */ 18 | 01882F1B19BFCD21006994D0 /* HRCoderTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HRCoderTests.m; sourceTree = ""; }; 19 | 01882F1E19BFCD29006994D0 /* HRCoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HRCoder.h; sourceTree = ""; }; 20 | 01882F1F19BFCD29006994D0 /* HRCoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HRCoder.m; sourceTree = ""; }; 21 | 01D28C6F1907BFC80021C719 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 22 | 01D28C711907BFC80021C719 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 23 | 01D28C731907BFC80021C719 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 24 | 01D28C871907BFC80021C719 /* UnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 25 | 01D28C881907BFC80021C719 /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 26 | 01D28C901907BFC80021C719 /* UnitTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "UnitTests-Info.plist"; sourceTree = ""; }; 27 | /* End PBXFileReference section */ 28 | 29 | /* Begin PBXFrameworksBuildPhase section */ 30 | 01D28C841907BFC80021C719 /* Frameworks */ = { 31 | isa = PBXFrameworksBuildPhase; 32 | buildActionMask = 2147483647; 33 | files = ( 34 | 01D28C891907BFC80021C719 /* XCTest.framework in Frameworks */, 35 | 01D28C8B1907BFC80021C719 /* UIKit.framework in Frameworks */, 36 | 01D28C8A1907BFC80021C719 /* Foundation.framework in Frameworks */, 37 | ); 38 | runOnlyForDeploymentPostprocessing = 0; 39 | }; 40 | /* End PBXFrameworksBuildPhase section */ 41 | 42 | /* Begin PBXGroup section */ 43 | 01882F1D19BFCD29006994D0 /* HRCoder */ = { 44 | isa = PBXGroup; 45 | children = ( 46 | 01882F1E19BFCD29006994D0 /* HRCoder.h */, 47 | 01882F1F19BFCD29006994D0 /* HRCoder.m */, 48 | ); 49 | name = HRCoder; 50 | path = ../HRCoder; 51 | sourceTree = ""; 52 | }; 53 | 01D28C631907BFC80021C719 = { 54 | isa = PBXGroup; 55 | children = ( 56 | 01882F1D19BFCD29006994D0 /* HRCoder */, 57 | 01D28C8E1907BFC80021C719 /* UnitTests */, 58 | 01D28C6E1907BFC80021C719 /* Frameworks */, 59 | 01D28C6D1907BFC80021C719 /* Products */, 60 | ); 61 | sourceTree = ""; 62 | }; 63 | 01D28C6D1907BFC80021C719 /* Products */ = { 64 | isa = PBXGroup; 65 | children = ( 66 | 01D28C871907BFC80021C719 /* UnitTests.xctest */, 67 | ); 68 | name = Products; 69 | sourceTree = ""; 70 | }; 71 | 01D28C6E1907BFC80021C719 /* Frameworks */ = { 72 | isa = PBXGroup; 73 | children = ( 74 | 01D28C6F1907BFC80021C719 /* Foundation.framework */, 75 | 01D28C711907BFC80021C719 /* CoreGraphics.framework */, 76 | 01D28C731907BFC80021C719 /* UIKit.framework */, 77 | 01D28C881907BFC80021C719 /* XCTest.framework */, 78 | ); 79 | name = Frameworks; 80 | sourceTree = ""; 81 | }; 82 | 01D28C8E1907BFC80021C719 /* UnitTests */ = { 83 | isa = PBXGroup; 84 | children = ( 85 | 01882F1B19BFCD21006994D0 /* HRCoderTests.m */, 86 | 01D28C8F1907BFC80021C719 /* Supporting Files */, 87 | ); 88 | path = UnitTests; 89 | sourceTree = ""; 90 | }; 91 | 01D28C8F1907BFC80021C719 /* Supporting Files */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | 01D28C901907BFC80021C719 /* UnitTests-Info.plist */, 95 | ); 96 | name = "Supporting Files"; 97 | sourceTree = ""; 98 | }; 99 | /* End PBXGroup section */ 100 | 101 | /* Begin PBXNativeTarget section */ 102 | 01D28C861907BFC80021C719 /* UnitTests */ = { 103 | isa = PBXNativeTarget; 104 | buildConfigurationList = 01D28C9B1907BFC80021C719 /* Build configuration list for PBXNativeTarget "UnitTests" */; 105 | buildPhases = ( 106 | 01D28C831907BFC80021C719 /* Sources */, 107 | 01D28C841907BFC80021C719 /* Frameworks */, 108 | 01D28C851907BFC80021C719 /* Resources */, 109 | ); 110 | buildRules = ( 111 | ); 112 | dependencies = ( 113 | ); 114 | name = UnitTests; 115 | productName = OSCacheTests; 116 | productReference = 01D28C871907BFC80021C719 /* UnitTests.xctest */; 117 | productType = "com.apple.product-type.bundle.unit-test"; 118 | }; 119 | /* End PBXNativeTarget section */ 120 | 121 | /* Begin PBXProject section */ 122 | 01D28C641907BFC80021C719 /* Project object */ = { 123 | isa = PBXProject; 124 | attributes = { 125 | LastUpgradeCheck = 0900; 126 | ORGANIZATIONNAME = "Charcoal Design"; 127 | TargetAttributes = { 128 | 01D28C861907BFC80021C719 = { 129 | TestTargetID = 01D28C6B1907BFC80021C719; 130 | }; 131 | }; 132 | }; 133 | buildConfigurationList = 01D28C671907BFC80021C719 /* Build configuration list for PBXProject "UnitTests" */; 134 | compatibilityVersion = "Xcode 3.2"; 135 | developmentRegion = English; 136 | hasScannedForEncodings = 0; 137 | knownRegions = ( 138 | en, 139 | ); 140 | mainGroup = 01D28C631907BFC80021C719; 141 | productRefGroup = 01D28C6D1907BFC80021C719 /* Products */; 142 | projectDirPath = ""; 143 | projectRoot = ""; 144 | targets = ( 145 | 01D28C861907BFC80021C719 /* UnitTests */, 146 | ); 147 | }; 148 | /* End PBXProject section */ 149 | 150 | /* Begin PBXResourcesBuildPhase section */ 151 | 01D28C851907BFC80021C719 /* Resources */ = { 152 | isa = PBXResourcesBuildPhase; 153 | buildActionMask = 2147483647; 154 | files = ( 155 | ); 156 | runOnlyForDeploymentPostprocessing = 0; 157 | }; 158 | /* End PBXResourcesBuildPhase section */ 159 | 160 | /* Begin PBXSourcesBuildPhase section */ 161 | 01D28C831907BFC80021C719 /* Sources */ = { 162 | isa = PBXSourcesBuildPhase; 163 | buildActionMask = 2147483647; 164 | files = ( 165 | 01882F1C19BFCD21006994D0 /* HRCoderTests.m in Sources */, 166 | 01882F2019BFCD29006994D0 /* HRCoder.m in Sources */, 167 | ); 168 | runOnlyForDeploymentPostprocessing = 0; 169 | }; 170 | /* End PBXSourcesBuildPhase section */ 171 | 172 | /* Begin XCBuildConfiguration section */ 173 | 01D28C961907BFC80021C719 /* Debug */ = { 174 | isa = XCBuildConfiguration; 175 | buildSettings = { 176 | ALWAYS_SEARCH_USER_PATHS = NO; 177 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 178 | CLANG_CXX_LIBRARY = "libc++"; 179 | CLANG_ENABLE_MODULES = NO; 180 | CLANG_ENABLE_OBJC_ARC = YES; 181 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 182 | CLANG_WARN_BOOL_CONVERSION = YES; 183 | CLANG_WARN_COMMA = YES; 184 | CLANG_WARN_CONSTANT_CONVERSION = YES; 185 | CLANG_WARN_CXX0X_EXTENSIONS = YES; 186 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 187 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 188 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 189 | CLANG_WARN_EMPTY_BODY = YES; 190 | CLANG_WARN_ENUM_CONVERSION = YES; 191 | CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; 192 | CLANG_WARN_INFINITE_RECURSION = YES; 193 | CLANG_WARN_INT_CONVERSION = YES; 194 | CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES; 195 | CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; 196 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 197 | CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = YES; 198 | CLANG_WARN_OBJC_RECEIVER_WEAK = YES; 199 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES; 200 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 201 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 202 | CLANG_WARN_STRICT_PROTOTYPES = YES; 203 | CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; 204 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 205 | CLANG_WARN_UNREACHABLE_CODE = YES; 206 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 207 | CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES; 208 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 209 | COPY_PHASE_STRIP = NO; 210 | ENABLE_STRICT_OBJC_MSGSEND = YES; 211 | ENABLE_TESTABILITY = YES; 212 | GCC_C_LANGUAGE_STANDARD = gnu99; 213 | GCC_DYNAMIC_NO_PIC = NO; 214 | GCC_NO_COMMON_BLOCKS = YES; 215 | GCC_OPTIMIZATION_LEVEL = 0; 216 | GCC_PREPROCESSOR_DEFINITIONS = ( 217 | "DEBUG=1", 218 | "$(inherited)", 219 | ); 220 | GCC_SHORT_ENUMS = YES; 221 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 222 | GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; 223 | GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; 224 | GCC_TREAT_WARNINGS_AS_ERRORS = YES; 225 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 226 | GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; 227 | GCC_WARN_ABOUT_MISSING_NEWLINE = YES; 228 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; 229 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 230 | GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES; 231 | GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES; 232 | GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; 233 | GCC_WARN_MULTIPLE_DEFINITION_TYPES_FOR_SELECTOR = YES; 234 | GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; 235 | GCC_WARN_PEDANTIC = YES; 236 | GCC_WARN_SHADOW = YES; 237 | GCC_WARN_SIGN_COMPARE = YES; 238 | GCC_WARN_STRICT_SELECTOR_MATCH = YES; 239 | GCC_WARN_UNDECLARED_SELECTOR = YES; 240 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 241 | GCC_WARN_UNKNOWN_PRAGMAS = YES; 242 | GCC_WARN_UNUSED_FUNCTION = YES; 243 | GCC_WARN_UNUSED_LABEL = YES; 244 | GCC_WARN_UNUSED_PARAMETER = YES; 245 | GCC_WARN_UNUSED_VARIABLE = YES; 246 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 247 | ONLY_ACTIVE_ARCH = YES; 248 | SDKROOT = iphoneos; 249 | WARNING_CFLAGS = ( 250 | "-Weverything", 251 | "-Wno-variadic-macros", 252 | "-Wno-gnu-zero-variadic-macro-arguments", 253 | "-Wno-gnu-statement-expression", 254 | "-Wno-objc-missing-property-synthesis", 255 | "-Wno-sign-compare", 256 | "-Wno-documentation-unknown-command", 257 | ); 258 | }; 259 | name = Debug; 260 | }; 261 | 01D28C971907BFC80021C719 /* Release */ = { 262 | isa = XCBuildConfiguration; 263 | buildSettings = { 264 | ALWAYS_SEARCH_USER_PATHS = NO; 265 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 266 | CLANG_CXX_LIBRARY = "libc++"; 267 | CLANG_ENABLE_MODULES = NO; 268 | CLANG_ENABLE_OBJC_ARC = YES; 269 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 270 | CLANG_WARN_BOOL_CONVERSION = YES; 271 | CLANG_WARN_COMMA = YES; 272 | CLANG_WARN_CONSTANT_CONVERSION = YES; 273 | CLANG_WARN_CXX0X_EXTENSIONS = YES; 274 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 275 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 276 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 277 | CLANG_WARN_EMPTY_BODY = YES; 278 | CLANG_WARN_ENUM_CONVERSION = YES; 279 | CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; 280 | CLANG_WARN_INFINITE_RECURSION = YES; 281 | CLANG_WARN_INT_CONVERSION = YES; 282 | CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES; 283 | CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES; 284 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 285 | CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = YES; 286 | CLANG_WARN_OBJC_RECEIVER_WEAK = YES; 287 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES; 288 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 289 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 290 | CLANG_WARN_STRICT_PROTOTYPES = YES; 291 | CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; 292 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 293 | CLANG_WARN_UNREACHABLE_CODE = YES; 294 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 295 | CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES; 296 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 297 | COPY_PHASE_STRIP = YES; 298 | ENABLE_NS_ASSERTIONS = NO; 299 | ENABLE_STRICT_OBJC_MSGSEND = YES; 300 | GCC_C_LANGUAGE_STANDARD = gnu99; 301 | GCC_NO_COMMON_BLOCKS = YES; 302 | GCC_SHORT_ENUMS = YES; 303 | GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; 304 | GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; 305 | GCC_TREAT_WARNINGS_AS_ERRORS = YES; 306 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 307 | GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES; 308 | GCC_WARN_ABOUT_MISSING_NEWLINE = YES; 309 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; 310 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 311 | GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES; 312 | GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES; 313 | GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES; 314 | GCC_WARN_MULTIPLE_DEFINITION_TYPES_FOR_SELECTOR = YES; 315 | GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES; 316 | GCC_WARN_PEDANTIC = YES; 317 | GCC_WARN_SHADOW = YES; 318 | GCC_WARN_SIGN_COMPARE = YES; 319 | GCC_WARN_STRICT_SELECTOR_MATCH = YES; 320 | GCC_WARN_UNDECLARED_SELECTOR = YES; 321 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 322 | GCC_WARN_UNKNOWN_PRAGMAS = YES; 323 | GCC_WARN_UNUSED_FUNCTION = YES; 324 | GCC_WARN_UNUSED_LABEL = YES; 325 | GCC_WARN_UNUSED_PARAMETER = YES; 326 | GCC_WARN_UNUSED_VARIABLE = YES; 327 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 328 | SDKROOT = iphoneos; 329 | VALIDATE_PRODUCT = YES; 330 | WARNING_CFLAGS = ( 331 | "-Weverything", 332 | "-Wno-variadic-macros", 333 | "-Wno-gnu-zero-variadic-macro-arguments", 334 | "-Wno-gnu-statement-expression", 335 | "-Wno-objc-missing-property-synthesis", 336 | "-Wno-sign-compare", 337 | "-Wno-documentation-unknown-command", 338 | ); 339 | }; 340 | name = Release; 341 | }; 342 | 01D28C9C1907BFC80021C719 /* Debug */ = { 343 | isa = XCBuildConfiguration; 344 | buildSettings = { 345 | FRAMEWORK_SEARCH_PATHS = ( 346 | "$(inherited)", 347 | "$(DEVELOPER_FRAMEWORKS_DIR)", 348 | ); 349 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 350 | GCC_PREPROCESSOR_DEFINITIONS = ( 351 | "DEBUG=1", 352 | "$(inherited)", 353 | ); 354 | INFOPLIST_FILE = "UnitTests/UnitTests-Info.plist"; 355 | PRODUCT_BUNDLE_IDENTIFIER = "com.charcoaldesign.${PRODUCT_NAME:rfc1034identifier}"; 356 | PRODUCT_NAME = UnitTests; 357 | TEST_HOST = "$(BUNDLE_LOADER)"; 358 | WRAPPER_EXTENSION = xctest; 359 | }; 360 | name = Debug; 361 | }; 362 | 01D28C9D1907BFC80021C719 /* Release */ = { 363 | isa = XCBuildConfiguration; 364 | buildSettings = { 365 | FRAMEWORK_SEARCH_PATHS = ( 366 | "$(inherited)", 367 | "$(DEVELOPER_FRAMEWORKS_DIR)", 368 | ); 369 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 370 | INFOPLIST_FILE = "UnitTests/UnitTests-Info.plist"; 371 | PRODUCT_BUNDLE_IDENTIFIER = "com.charcoaldesign.${PRODUCT_NAME:rfc1034identifier}"; 372 | PRODUCT_NAME = UnitTests; 373 | TEST_HOST = "$(BUNDLE_LOADER)"; 374 | WRAPPER_EXTENSION = xctest; 375 | }; 376 | name = Release; 377 | }; 378 | /* End XCBuildConfiguration section */ 379 | 380 | /* Begin XCConfigurationList section */ 381 | 01D28C671907BFC80021C719 /* Build configuration list for PBXProject "UnitTests" */ = { 382 | isa = XCConfigurationList; 383 | buildConfigurations = ( 384 | 01D28C961907BFC80021C719 /* Debug */, 385 | 01D28C971907BFC80021C719 /* Release */, 386 | ); 387 | defaultConfigurationIsVisible = 0; 388 | defaultConfigurationName = Release; 389 | }; 390 | 01D28C9B1907BFC80021C719 /* Build configuration list for PBXNativeTarget "UnitTests" */ = { 391 | isa = XCConfigurationList; 392 | buildConfigurations = ( 393 | 01D28C9C1907BFC80021C719 /* Debug */, 394 | 01D28C9D1907BFC80021C719 /* Release */, 395 | ); 396 | defaultConfigurationIsVisible = 0; 397 | defaultConfigurationName = Release; 398 | }; 399 | /* End XCConfigurationList section */ 400 | }; 401 | rootObject = 01D28C641907BFC80021C719 /* Project object */; 402 | } 403 | -------------------------------------------------------------------------------- /Tests/UnitTests.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Tests/UnitTests.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Tests/UnitTests.xcodeproj/xcshareddata/xcschemes/UnitTests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 16 | 18 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 41 | 42 | 43 | 44 | 50 | 51 | 53 | 54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Tests/UnitTests/HRCoderTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // HRCoderTests.m 3 | // 4 | // Created by Nick Lockwood on 12/01/2012. 5 | // Copyright (c) 2012 Charcoal Design. All rights reserved. 6 | // 7 | 8 | 9 | #import 10 | #import "HRCoder.h" 11 | 12 | 13 | @interface Model : NSObject 14 | 15 | @property (nonatomic, strong) NSString *text2; 16 | @property (nonatomic, strong) NSString *textNew; 17 | @property (nonatomic, copy) NSArray *array1; 18 | @property (nonatomic, copy) NSArray *array2; 19 | 20 | @end 21 | 22 | @implementation Model 23 | 24 | - (id)initWithCoder:(NSCoder *)aDecoder 25 | { 26 | _text2 = [aDecoder decodeObjectForKey:@"text2"]; 27 | _textNew = [aDecoder decodeObjectForKey:@"textNew"]; 28 | _array1 = [aDecoder decodeObjectForKey:@"array1"]; 29 | _array2 = [aDecoder decodeObjectForKey:@"array2"]; 30 | return self; 31 | } 32 | 33 | - (void)encodeWithCoder:(NSCoder *)aCoder 34 | { 35 | [aCoder encodeObject:self.text2 forKey:@"text2"]; 36 | [aCoder encodeObject:self.textNew forKey:@"textNew"]; 37 | [aCoder encodeObject:self.array1 forKey:@"array1"]; 38 | [aCoder encodeObject:self.array2 forKey:@"array2"]; 39 | } 40 | 41 | @end 42 | 43 | 44 | @interface HRCoderTests : XCTestCase 45 | 46 | @end 47 | 48 | @implementation HRCoderTests 49 | 50 | - (void)testChangingModel 51 | { 52 | //simulate saved model 53 | NSDictionary *dict = @{HRCoderClassNameKey: @"Model", @"text1": @"Foo", @"text2": @"Bar"}; 54 | 55 | //load as new model 56 | Model *model = [HRCoder unarchiveObjectWithPlistOrJSON:dict]; 57 | 58 | //check properties 59 | XCTAssertEqualObjects(model.text2, @"Bar"); 60 | XCTAssertNil(model.textNew); 61 | } 62 | 63 | - (void)testAliasing 64 | { 65 | Model *model = [[Model alloc] init]; 66 | model.array1 = @[@1, @2]; 67 | model.array2 = model.array1; 68 | 69 | //seralialize 70 | NSData *data = [HRCoder archivedDataWithRootObject:model]; 71 | 72 | //load as new model 73 | model = [HRCoder unarchiveObjectWithData:data]; 74 | 75 | //check properties 76 | XCTAssertEqualObjects(model.array1, model.array2); 77 | XCTAssertEqual(model.array1, model.array2); 78 | 79 | //now make them different but equal 80 | model.array2 = @[@1, @2]; 81 | 82 | //seralialize 83 | data = [HRCoder archivedDataWithRootObject:model]; 84 | 85 | //load as new model 86 | model = [HRCoder unarchiveObjectWithData:data]; 87 | 88 | //check properties 89 | XCTAssertEqualObjects(model.array1, model.array2); 90 | XCTAssertNotEqual(model.array1, model.array2); 91 | } 92 | 93 | - (void)testPlistData 94 | { 95 | //encode null 96 | NSArray *array = @[[NSNull null]]; 97 | 98 | //seralialize 99 | NSDictionary *plist = [HRCoder archivedPlistWithRootObject:array]; 100 | 101 | //convert to plist data 102 | NSError *error = nil; 103 | NSData *output = [NSPropertyListSerialization dataWithPropertyList:plist format:NSPropertyListXMLFormat_v1_0 options:0 error:&error]; 104 | XCTAssertNotNil(output); 105 | XCTAssertNil(error); 106 | } 107 | 108 | - (void)testJSONData 109 | { 110 | //encode date and data 111 | NSArray *array = @[ 112 | [NSDate date], 113 | (NSData *__nonnull)[@"foo" dataUsingEncoding:NSUTF8StringEncoding], 114 | [NSMutableString stringWithString:@"bar"] 115 | ]; 116 | 117 | //seralialize 118 | NSDictionary *json = [HRCoder archivedJSONWithRootObject:array]; 119 | 120 | //convert to json data 121 | NSError *error = nil; 122 | NSData *output = [NSJSONSerialization dataWithJSONObject:json options:(NSJSONWritingOptions)0 error:&error]; 123 | XCTAssertNotNil(output); 124 | XCTAssertNil(error); 125 | 126 | //convert back 127 | NSArray *result = [HRCoder unarchiveObjectWithData:output]; 128 | XCTAssertEqualObjects(result, array); 129 | } 130 | 131 | @end 132 | -------------------------------------------------------------------------------- /Tests/UnitTests/UnitTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | --------------------------------------------------------------------------------