[swift-corelibs-dev] NSCoding methods

Philippe Hausler phausler at apple.com
Wed Dec 23 16:48:46 CST 2015


The archiving format encodes the names of the classes in the archive itself. Here are a few code examples and a quasi readable output from them:

let uuid = NSUUID()
let data = NSKeyedArchiver.archivedDataWithRootObject(uuid)
let archive = try! NSPropertyListSerialization.propertyListWithData(data, options: [], format: nil)
print(archive)

prints the following:

{
    "$archiver" = NSKeyedArchiver;
    "$objects" =     (
        "$null",
                {
            "$class" = "<CFKeyedArchiverUID 0x1030025e0 [0x7fff7ab33bb0]>{value = 2}";
            "NS.uuidbytes" = <797639fe dad74b14 902afab3 c490448b>;
        },
                {
            "$classes" =             (
                NSUUID,
                NSObject
            );
            "$classname" = NSUUID;
        }
    );
    "$top" =     {
        root = "<CFKeyedArchiverUID 0x103002a80 [0x7fff7ab33bb0]>{value = 1}";
    };
    "$version" = 100000;
}

Note the $classes and $classname objects; which are what tell the internal implementation of NSKeyedUnarchiver what to construct; moreover you can create your own classes..

// I don’t really think this is a good naming for an application’s class but hey it might happen...
class NSUUID : NSObject, NSCoding {
    let uuid: Foundation.NSUUID
    required init?(coder aDecoder: NSCoder) {
        uuid = aDecoder.decodeObjectForKey("my.uuid") as! Foundation.NSUUID
    }
    override init() {
        uuid = Foundation.NSUUID()
    }
    func encodeWithCoder(aCoder: NSCoder) {
        aCoder.encodeObject(uuid, forKey: "my.uuid")
    }
}

let uuid = NSUUID()
let data = NSKeyedArchiver.archivedDataWithRootObject(uuid)
let archive = try! NSPropertyListSerialization.propertyListWithData(data, options: [], format: nil)
print(archive)

prints the following:

{
    "$archiver" = NSKeyedArchiver;
    "$objects" =     (
        "$null",
                {
            "$class" = "<CFKeyedArchiverUID 0x100709630 [0x7fff7ab33bb0]>{value = 4}";
            "my.uuid" = "<CFKeyedArchiverUID 0x100708e60 [0x7fff7ab33bb0]>{value = 2}";
        },
                {
            "$class" = "<CFKeyedArchiverUID 0x100709740 [0x7fff7ab33bb0]>{value = 3}";
            "NS.uuidbytes" = <546e5b5e 15c244a1 aa96eb90 30c3f7f6>;
        },
                {
            "$classes" =             (
                NSUUID,
                NSObject
            );
            "$classname" = NSUUID;
        },
                {
            "$classes" =             (
                "Archiver.NSUUID",
                NSObject
            );
            "$classname" = "Archiver.NSUUID";
        }
    );
    "$top" =     {
        root = "<CFKeyedArchiverUID 0x100709b70 [0x7fff7ab33bb0]>{value = 1}";
    };
    "$version" = 100000;
}

Granted this is a questionable name for a class but it illustrates which class names are encoded where and how they should be interpreted in the pre-existing archive format; which we will have to figure out some sensible way of inflating and deflating to/from disk/network etc.

> On Dec 23, 2015, at 2:37 PM, Jordan Rose <jordan_rose at apple.com> wrote:
> 
> No, we cannot encode things "non-mangled but with the namespace". For any type other than top-level non-generic class types, using a non-mangled name is not unique. The only correct answer for arbitrary classes is to use mangled names, or something that maps one-to-one with mangled names.
> 
> Now, Foundation classes are not arbitrary classes, but then I don't see why we'd need to use mangled names for those. We can just use the plain old Objective-C names that the OS X classes use today.
> 
> Jordan
> 
>> On Dec 22, 2015, at 10:16, Philippe Hausler via swift-corelibs-dev <swift-corelibs-dev at swift.org <mailto:swift-corelibs-dev at swift.org>> wrote:
>> 
>> To clarify the goals: I think it is reasonable for us to have a goal to be able to encode/decode archives from foreign targets; e.g. linux encodes an archive and mac os x decodes or iOS encodes and linux decodes. This will allow for server architecture to transmit binary archives across the wire. This will mean that we will want to have the encoded class names from the application scope to be encoded as the non mangled name but with the namespace. However this presents a problem; Foundation will have a namespace which will need to be inferred both for encoding and decoding. Thankfully there may be a reasonable way to approach this;
>> 
>> public class func classNameForClass(cls: AnyClass) -> String?
>> public class func setClassName(codedName: String?, forClass cls: AnyClass)
>> 
>> These methods can be used to allow for translation of classes by registering the appropriate classes for a “shortened” name that drops the Foundation/SwiftFoundation namespace prefix during encoding.
>> 
>>> On Dec 22, 2015, at 2:45 AM, Luke Howard via swift-corelibs-dev <swift-corelibs-dev at swift.org <mailto:swift-corelibs-dev at swift.org>> wrote:
>>> 
>>> 
>>>> On 22 Dec 2015, at 5:50 AM, Jordan Rose <jordan_rose at apple.com <mailto:jordan_rose at apple.com>> wrote:
>>>> 
>>>> IMHO on Linux NSKeyedArchiver should always use mangled names. If we want cross-platform archives, we should set up standard substitutions, but given that Swift classes exposed to Objective-C are archived with their full names it doesn't make sense to use "half the name" in the archive.
>>> 
>>> You mean namespaced but unmangled yes? If so I agree.
>>> 
>>> BTW I found a couple of small CF nits:
>>> 
>>> * in CFDictionaryGetKeysAndValues(), keybuf and valuebuf are transposed in the call to CF_SWIFT_FUNCDISPATCHV(NSDictionary.getObjects())
>>> 
>>> * _CFSwiftDictionaryGetKeysAndValues() does not handle keybuf or valbuf being NULL (either of which are valid when calling CFDictionaryGetKeysAndValues())
>>> 
>> 
>> This is a bit un-related to NSCoding and the transposition is probably a mistake if it is inverted (the CF method should be reversed from the NS method to mimic the objc counterpart)
>> 
>>> — Luke
>>> _______________________________________________
>>> swift-corelibs-dev mailing list
>>> swift-corelibs-dev at swift.org <mailto:swift-corelibs-dev at swift.org>
>>> https://lists.swift.org/mailman/listinfo/swift-corelibs-dev <https://lists.swift.org/mailman/listinfo/swift-corelibs-dev>
>> 
>> _______________________________________________
>> swift-corelibs-dev mailing list
>> swift-corelibs-dev at swift.org <mailto:swift-corelibs-dev at swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-corelibs-dev <https://lists.swift.org/mailman/listinfo/swift-corelibs-dev>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-corelibs-dev/attachments/20151223/8023353c/attachment.html>


More information about the swift-corelibs-dev mailing list