Subclassing NSCoder

NSCoder’s interface is quite general and extensive, declaring methods to encode and decode objects and values with and without keys. Concrete subclasses are not required to properly implement all of NSCoder’s methods and may explicitly restrict themselves to certain types of operations. For example, NSArchiver does not implement the decode... methods, and NSUnarchiver does not implement the encode... methods. In addition, neither class implements the keyed coding methods for encoding and decoding keyed archives. Invoking a decode method on NSArchiver or an encode method on NSUnarchiver raises an NSInvalidArgumentException.

If you define a subclass of NSCoder that does not support keyed coding, at a minimum your subclass must override the following methods:

If your subclass supports keyed coding, you must override the above methods as well as the allowsKeyedCoding method (to return YES) and all of the keyed coding methods defined by NSCoder. In both cases, if you are creating separate classes for encoding and decoding, you do not need to override the encode methods in the decoder class nor the decode methods in the encoder class.

Note that encodeObject: and decodeObject are not among the basic methods. They are defined abstractly to invoke encodeValueOfObjCType:at: or decodeValueOfObjCType:at: with an Objective-C type code of “@”. Your implementations of the latter two methods must handle this case, invoking the object’s encodeWithCoder: or initWithCoder: method and sending the proper substitution messages (as described in “Making Substitutions During Coding”) to the object before encoding it and after decoding it.

Your subclass may override other methods to provide specialized handling for certain situations. In particular, you can implement any of the following methods:

See the individual method descriptions for more information on their required behavior. The default NSCoder implementations of these methods just invoke encodeObject:.

If you override encodeConditionalObject: to support conditional objects (see “Conditional Objects”), be aware that the first unconditional encoding may occur after any number of conditional encoding requests, so your coder will not know which conditional objects to encode until all the other objects have been encoded.

With objects, the object being coded is fully responsible for coding itself. However, a few classes hand this responsibility back to the coder object, either for performance reasons or because proper support depends on more information than the object itself has. The notable classes in Foundation that do this are NSData and NSPort. NSData’s low-level nature makes optimization important. For this reason, an NSData object always asks its coder to handle its contents directly using the encodeDataObject: and decodeDataObject methods when it receives the encodeWithCoder: and initWithCoder: messages. Similarly, an NSPort object asks its coder to handle it using the encodePortObject: and decodePortObject methods (which only NSPortCoder implements). This is because an NSPort represents information kept in the operating system itself, which requires special handling for transmission to another process.

These special cases don’t affect users of coder objects, since the redirection is handled by the classes themselves in their NSCoding protocol methods. An implementor of a concrete coder subclass, however, must implement the appropriate custom methods to encode and decode NSData and (if relevant) NSPort objects itself.