Skip to content

AutoCoding is a category on NSObject that provides automatic support for NSCoding to any object.

License

Notifications You must be signed in to change notification settings

zhuolaiqiang/AutoCoding

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Purpose

AutoCoding is a category on NSObject that provides automatic support for NSCoding and NSCopying to any object. This means that rather than having to implement the initWithCoder:, encodeWithCoder: and copyWithZone: methods yourself, all the model classes in your app can be saved or loaded from a file without you needing to write any additional code.

Of course no automated system can read your mind, so AutoCoding does place certain restrictions on how you design your classes; For example, you should avoid using structs that are not already NSCoding-compliant via NSValue, and if your class should be deep (as opposed to shallow) copied, or needs to implement NSMutableCopying instead, then you will still need to provide your own copying implementation.

However, use of AutoCoding is by no means and all-or-nothing decision. You are free to implement your own NSCoding or NSCopying methods on any class in your project and they will simply override the automatically generated methods.

AutoCoding is also designed to work hand-in-hand with the BaseModel library (https://github.com/nicklockwood/BaseModel) to form the basis for building a powerful model hierarchy for your project with minimal effort. Check the AutoCoding example included in the BaseModel repository for an example of the AutoCoding library in action.

Supported OS & SDK Versions

  • Supported build target - iOS 6.0 / Mac OS 10.8 (Xcode 4.5.2, Apple LLVM compiler 4.1)
  • Earliest supported deployment target - iOS 5.0 / Mac OS 10.7
  • Earliest compatible deployment target - iOS 4.3 / Mac OS 10.6

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.

ARC Compatibility

AutoCoding is compatible with both ARC and non-ARC compile targets.

Thread Safety

AutoCoding is fully thread-safe.

Installation

To use the AutoCoding category in your project, just drag the AutoCoding .h and .m files into your project.

Category methods

The NSObject(AutoCoding) category extends NSObject with the following methods. Since this is a category, every single Cocoa object, including AppKit/UIKit objects and BaseModel instances inherit these methods.

+ (NSArray *)codableKeys;

This method returns an array containing the names of all the properties of the class that will be automatically saved, loaded and copied when the object is archived using NSKeyedArchiver/Unarchiver or copied using the NSCopying protocol. This array is automatically generated by scanning the properties defined in the class definition at runtime. Read-only and private properties will also be coded as long as they have KVC-compliant ivar names (i.e. the ivar matches the property name, or is the same but with a _ prefix). It is not normally necessary to override this method unless you wish to add ivars for coding that do not have matching property definitions. If you wish to exclude certain properties from the serialisation process, you can return them in the uncodableKeys method and they will be automatically removed from this array. Note that this method only returns the properties defined on a particular class and not any properties that are inherited from its superclasses. You do not need to call [super uncodableKeys] if you override this method.

+ (NSArray *)uncodableKeys;

This method can be used to exclude certain properties from automatic coding without having to override or re-implement the codableKeys method. The default return value of this method is nil. Implement the method and return an array containing the names of any properties you wish to exclude from coding or copying. You do not need to call [super uncodableKeys] if you override this method.

- (NSArray *)codableKeys;

This method returns all the codable properties of the object, including those that are inherited from superclasses. You should not override this method.

- (NSDictionary *)dictionaryRepresentation;

This method returns a dictionary of the values of all the codable properties of the object. It is equivalent to calling dictionaryWithValuesForKeys: with the result of the codableKeys method as the parameter.

- (void)setWithCoder:(NSCoder *)coder;

This method populates the object's properties using the provided coder object, based on the codableKeys array. This is called internally by the initWithCoder: method, but may be useful if you wish to initialise an object from a coder archive after it has already been created. You could even initialise the object by merging the results of several different archives by calling setWithCoder: more than once.

+ (instancetype)objectWithContentsOfFile:(NSString *)path;

This attempts to load the file using the following sequence: 1) If the file is an NSCoded archive, load the root object and return it, 2) If the file is an ordinary Plist, load and return the root object, 3) Return the raw data as an NSData object. If the de-serialised object is not a subclass of the class being used to load it, an exception will be thrown (to avoid this, call the method on NSObject instead of a specific subclass).

- (BOOL)writeToFile:(NSString *)filePath atomically:(BOOL)useAuxiliaryFile;

This attempts to write the file to disk. This method is overridden by the equivalent methods for NSData, NSDictionary and NSArray, which save the file as a human-readable XML Plist rather than an binary NSCoded Plist archive, but the objectWithContentsOfFile: method will correctly de-serialise these again anyway. For any other object it will serialise the object using the NSCoding protocol and write out the file as a NSCoded binary Plist archive. Returns YES on success and NO on failure.

Tips

  1. If you want to perform initialisation of the class post or prior to the properties being loaded via NSCoding, override the setWithCoder: method and call the super-implementation before or after applying your own logic, like this:

    • (void)setWithCoder:(NSCoder *)coder { //pre-initialisation [super setWithCoder:coder]; //post-initialisation }

Note that unlike in previous versions, the init method is not called when using initWithCoder:.

  1. If you want to perform some cleanup or post-processing or substitute a different object after the object has been loaded via NSCoding, you can use the awakeAfterUsingCoder: method, which is defined in the NSObject class reference.

  2. You can add additional coding/decoding logic by overriding the setWithCoder: and/or encodeWithCoder: methods. As long as you call the [super ...] implementation, the auto-coding will still function.

  3. If you wish to substitute a different class for properties of a given type - for example if you have changed the name of a class but wish to retain compatibility with files saved using the old class name, you can substitute a different class for a given name by using the [NSKeyedUnArchiver setClass:forClassName:] method.

  4. If you have properties of a type that doesn't support NSCoding (e.g. a struct), and you wish to code them yourself by applying a conversion function, return the name of the property in the uncodableKeys array and override the setWithCoder: and encodeWithCoder: methods (remembering to call the super-implementations of those methods to automatically load and save the other properties of the object). Like this:

    • (NSArray *)uncodableKeys { return @[@"uncodableProperty"]; }
    • (void)setWithCoder:(NSCoder *)coder { [super setWithCoder:coder]; self.uncodableProperty = DECODE_VALUE([coder decodeObjectForKey:@"uncodableProperty"]; }

    • (void)encodeWithCoder:(NSCoder *)coder { [super encodeWithCoder:coder]; [coder encodeObject:ENCODE_VALUE(self.newProperty) forKey:@"uncodableProperty"]; }

  5. If you have changed the name of a property, but want to check for the existence of the old key name for backwards compatibility, override the setWithCoder: method and add a check for the old property as follows:

    • (void)setWithCoder:(NSCoder *)coder { [super setWithCoder:coder]; self.newProperty = [coder objectForKey:@"oldProperty"] ?: self.newProperty; }
  6. If you have changed the name of a property, but want to load and save it using the old key name for backwards compatibility, return the name of the new property in the uncodableKeys array and override the setWithCoder:, encodeWithCoder: and copyWithZone: methods to save and load the property using the old name (remembering to call the super-implementations of those methods to automatically load and save the other properties of the object). Like this:

    • (NSArray *)uncodableKeys { return @[@"newProperty"]; }
    • (void)setWithCoder:(NSCoder *)coder { [super setWithCoder:coder]; self.newProperty = [coder objectForKey:@"oldProperty"]; }

    • (void)encodeWithCoder:(NSCoder *)coder { [super encodeWithCoder:coder]; [coder encodeObject:self.newProperty forKey:@"oldProperty"]; }

    • (id)copyWithZone:(NSZone *)zone { id copy = [super copyWithZone:zone]; [copy setValue:self.newProperty forKey:@"newProperty"]; return copy; }

About

AutoCoding is a category on NSObject that provides automatic support for NSCoding to any object.

Resources

License

Stars

Watchers

Forks

Packages

No packages published